library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------------------------------------------------------------------------------------------------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.0.6     v dplyr   1.0.4
v tidyr   1.1.2     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.1
-- Conflicts ------------------------------------------------------------------------------------------------------------------------------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(knitr)
library(highcharter)
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Highcharts (www.highcharts.com) is a Highsoft software product which is
not free for commercial and Governmental use
library(plotly)

Attaching package: 㤼㸱plotly㤼㸲

The following object is masked from 㤼㸱package:ggplot2㤼㸲:

    last_plot

The following object is masked from 㤼㸱package:stats㤼㸲:

    filter

The following object is masked from 㤼㸱package:graphics㤼㸲:

    layout
library(viridis)
Loading required package: viridisLite
library(wesanderson)
library(plotly)
library(countrycode)
library(visNetwork)
library(randomcoloR)
survey <- read.csv("F:\\DataViz\\Project\\survey_results_public.csv")
schema <- read.csv("F:\\DataViz\\Project\\survey_results_schema.csv")

The datasets have been imported. survey represents the results of the survey schema represents the questions asked during the survey.

Before exploring the results of the survey, let us take a look at the questions asked during the survey.

kable(schema)
Column QuestionText
Respondent Randomized respondent ID number (not in order of survey response time)
Hobby Do you code as a hobby?
OpenSource Do you contribute to open source projects?
Country In which country do you currently reside?
Student Are you currently enrolled in a formal, degree-granting college or university program?
Employment Which of the following best describes your current employment status?
FormalEducation Which of the following best describes the highest level of formal education that you’ve completed?
UndergradMajor You previously indicated that you went to a college or university. Which of the following best describes your main field of study (aka ‘major’)
CompanySize Approximately how many people are employed by the company or organization you work for?
DevType Which of the following describe you? Please select all that apply.
YearsCoding Including any education, for how many years have you been coding?
YearsCodingProf For how many years have you coded professionally (as a part of your work)?
JobSatisfaction How satisfied are you with your current job? If you work more than one job, please answer regarding the one you spend the most hours on.
CareerSatisfaction Overall, how satisfied are you with your career thus far?
HopeFiveYears Which of the following best describes what you hope to be doing in five years?
JobSearchStatus Which of the following best describes your current job-seeking status?
LastNewJob When was the last time that you took a job with a new employer?
AssessJob1 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. The industry that I’d be working in
AssessJob2 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. The financial performance or funding status of the company or organization
AssessJob3 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. The specific department or team I’d be working on
AssessJob4 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. The languages, frameworks, and other technologies I’d be working with
AssessJob5 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. The compensation and benefits offered
AssessJob6 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. The office environment or company culture
AssessJob7 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. The opportunity to work from home/remotely
AssessJob8 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. Opportunities for professional development
AssessJob9 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. The diversity of the company or organization
AssessJob10 Imagine that you are assessing a potential job opportunity. Please rank the following aspects of the job opportunity in order of importance (by dragging the choices up and down), where 1 is the most important and 10 is the least important. How widely used or impactful the product or service I’d be working on is
AssessBenefits1 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Salary and/or bonuses
AssessBenefits2 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Stock options or shares
AssessBenefits3 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Health insurance
AssessBenefits4 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Parental leave
AssessBenefits5 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Fitness or wellness benefit (ex. gym membership, nutritionist)
AssessBenefits6 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Retirement or pension savings matching
AssessBenefits7 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Company-provided meals or snacks
AssessBenefits8 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Computer/office equipment allowance
AssessBenefits9 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Childcare benefit
AssessBenefits10 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Transportation benefit (ex. company-provided transportation, public transit allowance)
AssessBenefits11 Now, imagine you are assessing a job’s benefits package. Please rank the following aspects of a job’s benefits package from most to least important to you (by dragging the choices up and down), where 1 is most important and 11 is least important. Conference or education budget
JobContactPriorities1 Imagine that a company wanted to contact you about a job that is a good fit for you. Please rank your preference in how you are contacted (by dragging the choices up and down), where 1 is the most preferred and 5 is the least preferred. Telephone call
JobContactPriorities2 Imagine that a company wanted to contact you about a job that is a good fit for you. Please rank your preference in how you are contacted (by dragging the choices up and down), where 1 is the most preferred and 5 is the least preferred. Email to my private address
JobContactPriorities3 Imagine that a company wanted to contact you about a job that is a good fit for you. Please rank your preference in how you are contacted (by dragging the choices up and down), where 1 is the most preferred and 5 is the least preferred. Email to my work address
JobContactPriorities4 Imagine that a company wanted to contact you about a job that is a good fit for you. Please rank your preference in how you are contacted (by dragging the choices up and down), where 1 is the most preferred and 5 is the least preferred. Message on a job site
JobContactPriorities5 Imagine that a company wanted to contact you about a job that is a good fit for you. Please rank your preference in how you are contacted (by dragging the choices up and down), where 1 is the most preferred and 5 is the least preferred. Message on a social media site
JobEmailPriorities1 Imagine that same company decided to contact you through email. Please rank the following items by how important it is to include them in the message (by dragging the choices up and down), where 1 is the most important and 7 is the least important. Details on the company I’d be working for
JobEmailPriorities2 Imagine that same company decided to contact you through email. Please rank the following items by how important it is to include them in the message (by dragging the choices up and down), where 1 is the most important and 7 is the least important. Details on the specific department I’d be working for or product I’d be working on
JobEmailPriorities3 Imagine that same company decided to contact you through email. Please rank the following items by how important it is to include them in the message (by dragging the choices up and down), where 1 is the most important and 7 is the least important. Specifics of why they think I’d be a good fit for the role (ex. my prior work history, projects on GitHub)
JobEmailPriorities4 Imagine that same company decided to contact you through email. Please rank the following items by how important it is to include them in the message (by dragging the choices up and down), where 1 is the most important and 7 is the least important. Details of which technologies I’d be working with
JobEmailPriorities5 Imagine that same company decided to contact you through email. Please rank the following items by how important it is to include them in the message (by dragging the choices up and down), where 1 is the most important and 7 is the least important. An estimate of the compensation range
JobEmailPriorities6 Imagine that same company decided to contact you through email. Please rank the following items by how important it is to include them in the message (by dragging the choices up and down), where 1 is the most important and 7 is the least important. Information on the company’s hiring process
JobEmailPriorities7 Imagine that same company decided to contact you through email. Please rank the following items by how important it is to include them in the message (by dragging the choices up and down), where 1 is the most important and 7 is the least important. Details on the company’s product development process
UpdateCV Think back to the last time you updated your resumé, CV, or an online profile on a job site. What is the main reason that you did so?
Currency Which currency do you use day-to-day? If your answer is complicated, please pick the one you’re most comfortable estimating in.
Salary What is your current gross salary (before taxes and deductions), in ${q://QID50/ChoiceGroup/SelectedChoicesTextEntry}? Please enter a whole number in the box below, without any punctuation. If you are paid hourly, please estimate an equivalent weekly, monthly, or yearly salary. If you prefer not to answer, please leave the box empty.
SalaryType Is that salary weekly, monthly, or yearly?
ConvertedSalary Salary converted to annual USD salaries using the exchange rate on 2018-01-18, assuming 12 working months and 50 working weeks.
CurrencySymbol Three digit currency abbreviation.
CommunicationTools Which of the following tools do you use to communicate, coordinate, or share knowledge with your coworkers? Please select all that apply.
TimeFullyProductive Suppose a new developer with four years of experience, including direct experience working with your company’s main technical stack, joined your team tomorrow. All other things being equal, how long would you expect it to take before they were fully productive and contributing at a typical level to your main code base?
EducationTypes Which of the following types of non-degree education have you used or participated in? Please select all that apply.
SelfTaughtTypes You indicated that you had taught yourself a programming technology without taking a course. What resources did you use to do that? If you’ve done it more than once, please think about the most recent time you’ve done so. Please select all that apply.
TimeAfterBootcamp You indicated previously that you went through a developer training program or bootcamp. How long did it take you to get a full-time job as a developer after graduating?
HackathonReasons You indicated previously that you had participated in an online coding competition or hackathon. Which of the following best describe your reasons for doing so?
AgreeDisagree1 To what extent do you agree or disagree with each of the following statements? I feel a sense of kinship or connection to other developers
AgreeDisagree2 To what extent do you agree or disagree with each of the following statements? I think of myself as competing with my peers
AgreeDisagree3 To what extent do you agree or disagree with each of the following statements? I’m not as good at programming as most of my peers
LanguageWorkedWith Which of the following programming, scripting, and markup languages have you done extensive development work in over the past year, and which do you want to work in over the next year? (If you both worked with the language and want to continue to do so, please check both boxes in that row.)
LanguageDesireNextYear Which of the following programming, scripting, and markup languages have you done extensive development work in over the past year, and which do you want to work in over the next year? (If you both worked with the language and want to continue to do so, please check both boxes in that row.)
DatabaseWorkedWith Which of the following database environments have you done extensive development work in over the past year, and which do you want to work in over the next year? (If you both worked with the database and want to continue to do so, please check both boxes in that row.)
DatabaseDesireNextYear Which of the following database environments have you done extensive development work in over the past year, and which do you want to work in over the next year? (If you both worked with the database and want to continue to do so, please check both boxes in that row.)
PlatformWorkedWith Which of the following platforms have you done extensive development work for over the past year? (If you both developed for the platform and want to continue to do so, please check both boxes in that row.)
PlatformDesireNextYear Which of the following platforms have you done extensive development work for over the past year? (If you both developed for the platform and want to continue to do so, please check both boxes in that row.)
FrameworkWorkedWith Which of the following libraries, frameworks, and tools have you done extensive development work in over the past year, and which do you want to work in over the next year?
FrameworkDesireNextYear Which of the following libraries, frameworks, and tools have you done extensive development work in over the past year, and which do you want to work in over the next year?
IDE Which development environment(s) do you use regularly? Please check all that apply.
OperatingSystem What is the primary operating system in which you work?
NumberMonitors How many monitors are set up at your workstation?
Methodology Which of the following methodologies do you have experience working in?
VersionControl What version control systems do you use regularly? Please select all that apply.
CheckInCode Over the last year, how often have you checked-in or committed code?
AdBlocker Do you have ad-blocking software installed on any computers you use regularly?
AdBlockerDisable In the past month, have you disabled your ad blocker for any reason, even temporarily or for a specific website?
AdBlockerReasons What are the reasons that you have disabled your ad blocker in the past month? Please select all that apply.
AdsAgreeDisagree1 To what extent do you agree or disagree with the following statements: Online advertising can be valuable when it is relevant to me
AdsAgreeDisagree2 To what extent do you agree or disagree with the following statements: I enjoy seeing online updates from companies that I like
AdsAgreeDisagree3 To what extent do you agree or disagree with the following statements: I fundamentally dislike the concept of advertising
AdsActions Which of the following actions have you taken in the past month? Please select all that apply.
AdsPriorities1 Please rank the following advertising qualities in order of their importance to you (by dragging the choices up and down), where 1 is the most important, and 7 is the least important. The advertisement is relevant to me
AdsPriorities2 Please rank the following advertising qualities in order of their importance to you (by dragging the choices up and down), where 1 is the most important, and 7 is the least important. The advertisement is honest about its goals
AdsPriorities3 Please rank the following advertising qualities in order of their importance to you (by dragging the choices up and down), where 1 is the most important, and 7 is the least important. The advertisement provides useful information
AdsPriorities4 Please rank the following advertising qualities in order of their importance to you (by dragging the choices up and down), where 1 is the most important, and 7 is the least important. The advertisement seems trustworthy
AdsPriorities5 Please rank the following advertising qualities in order of their importance to you (by dragging the choices up and down), where 1 is the most important, and 7 is the least important. The advertisement is from a company that I like
AdsPriorities6 Please rank the following advertising qualities in order of their importance to you (by dragging the choices up and down), where 1 is the most important, and 7 is the least important. The advertisement offers something of value, like a free trial
AdsPriorities7 Please rank the following advertising qualities in order of their importance to you (by dragging the choices up and down), where 1 is the most important, and 7 is the least important. The advertisement avoids fluffy or vague language
AIDangerous What do you think is the most dangerous aspect of increasingly advanced AI technology?
AIInteresting What do you think is the most exciting aspect of increasingly advanced AI technology?
AIResponsible Whose responsibility is it, primarily, to consider the ramifications of increasingly advanced AI technology?
AIFuture Overall, what’s your take on the future of artificial intelligence?
EthicsChoice Imagine that you were asked to write code for a purpose or product that you consider extremely unethical. Do you write the code anyway?
EthicsReport Do you report or otherwise call out the unethical code in question?
EthicsResponsible Who do you believe is ultimately most responsible for code that accomplishes something unethical?
EthicalImplications Do you believe that you have an obligation to consider the ethical implications of the code that you write?
StackOverflowRecommend How likely is it that you would recommend Stack Overflow overall to a friend or colleague? Where 0 is not likely at all and 10 is very likely.
StackOverflowVisit How frequently would you say you visit Stack Overflow?
StackOverflowHasAccount Do you have a Stack Overflow account?
StackOverflowParticipate How frequently would you say you participate in Q&A on Stack Overflow? By participate we mean ask, answer, vote for, or comment on questions.
StackOverflowJobs Have you ever used or visited Stack Overflow Jobs?
StackOverflowDevStory Do you have an up-to-date Developer Story on Stack Overflow?
StackOverflowJobsRecommend How likely is it that you would recommend Stack Overflow Jobs to a friend or colleague? Where 0 is not likely at all and 10 is very likely.
StackOverflowConsiderMember Do you consider yourself a member of the Stack Overflow community?
HypotheticalTools1 Please rate your interest in participating in each of the following hypothetical tools on Stack Overflow, where 1 is not at all interested and 5 is extremely interested. A peer mentoring system
HypotheticalTools2 Please rate your interest in participating in each of the following hypothetical tools on Stack Overflow, where 1 is not at all interested and 5 is extremely interested. A private area for people new to programming
HypotheticalTools3 Please rate your interest in participating in each of the following hypothetical tools on Stack Overflow, where 1 is not at all interested and 5 is extremely interested. A programming-oriented blog platform
HypotheticalTools4 Please rate your interest in participating in each of the following hypothetical tools on Stack Overflow, where 1 is not at all interested and 5 is extremely interested. An employer or job review system
HypotheticalTools5 Please rate your interest in participating in each of the following hypothetical tools on Stack Overflow, where 1 is not at all interested and 5 is extremely interested. An area for Q&A related to career growth
WakeTime On days when you work, what time do you typically wake up?
HoursComputer On a typical day, how much time do you spend on a desktop or laptop computer?
HoursOutside On a typical day, how much time do you spend outside?
SkipMeals In a typical week, how many times do you skip a meal in order to be more productive?
ErgonomicDevices What ergonomic furniture or devices do you use on a regular basis? Please select all that apply.
Exercise In a typical week, how many times do you exercise?
Gender Which of the following do you currently identify as? Please select all that apply. If you prefer not to answer, you may leave this question blank.
SexualOrientation Which of the following do you currently identify as? Please select all that apply. If you prefer not to answer, you may leave this question blank.
EducationParents What is the highest level of education received by either of your parents? If you prefer not to answer, you may leave this question blank.
RaceEthnicity Which of the following do you identify as? Please check all that apply. If you prefer not to answer, you may leave this question blank.
Age What is your age? If you prefer not to answer, you may leave this question blank.
Dependents Do you have any children or other dependents that you care for? If you prefer not to answer, you may leave this question blank.
MilitaryUS Are you currently serving or have you ever served in the U.S. Military?
SurveyTooLong How do you feel about the length of the survey that you just completed?
SurveyEasy How easy or difficult was this survey to complete?
glimpse(survey)
Rows: 98,855
Columns: 129
$ Respondent                  <int> 1, 3, 4, 5, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21, 22, 26, 27, 29, 31, 33, 34, 37, 38, 39, 41, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61...
$ Hobby                       <fct> Yes, Yes, Yes, No, Yes, Yes, Yes, Yes, Yes, No, Yes, Yes, Yes, No, No, Yes, No, Yes, Yes, Yes, Yes, Yes, No, Yes, Yes, Yes, Yes, No, Yes, Yes, No, Yes, Yes, No...
$ OpenSource                  <fct> No, Yes, Yes, No, No, No, Yes, Yes, Yes, Yes, No, Yes, No, No, No, No, No, No, Yes, Yes, Yes, No, No, No, No, Yes, Yes, No, Yes, Yes, No, Yes, No, No, No, Yes,...
$ Country                     <fct> Kenya, United Kingdom, United States, United States, South Africa, United Kingdom, United States, Nigeria, United States, India, Spain, India, Croatia, India, ...
$ Student                     <fct> "No", "No", "No", "No", "Yes, part-time", "No", "No", "No", "No", "No", "No", "No", NA, "No", "Yes, full-time", "No", "Yes, full-time", "No", "Yes, full-time",...
$ Employment                  <fct> Employed part-time, Employed full-time, Employed full-time, Employed full-time, Employed full-time, Employed full-time, Employed full-time, Employed full-time,...
$ FormalEducation             <fct> "Bachelorâ\200\231s degree (BA, BS, B.Eng., etc.)", "Bachelorâ\200\231s degree (BA, BS, B.Eng., etc.)", "Associate degree", "Bachelorâ\200\231s degree (BA, BS,...
$ UndergradMajor              <fct> "Mathematics or statistics", "A natural science (ex. biology, chemistry, physics)", "Computer science, computer engineering, or software engineering", "Compute...
$ CompanySize                 <fct> "20 to 99 employees", "10,000 or more employees", "20 to 99 employees", "100 to 499 employees", "10,000 or more employees", "10 to 19 employees", "10,000 or mo...
$ DevType                     <fct> "Full-stack developer", "Database administrator;DevOps specialist;Full-stack developer;System administrator", "Engineering manager;Full-stack developer", "Full...
$ YearsCoding                 <fct> 3-5 years, 30 or more years, 24-26 years, 18-20 years, 6-8 years, 6-8 years, 9-11 years, 0-2 years, 30 or more years, 0-2 years, 6-8 years, 0-2 years, 0-2 year...
$ YearsCodingProf             <fct> 3-5 years, 18-20 years, 6-8 years, 12-14 years, 0-2 years, 3-5 years, 0-2 years, 3-5 years, 21-23 years, NA, 0-2 years, NA, NA, 3-5 years, 0-2 years, 3-5 years...
$ JobSatisfaction             <fct> Extremely satisfied, Moderately dissatisfied, Moderately satisfied, Neither satisfied nor dissatisfied, Slightly satisfied, Moderately satisfied, Slightly sati...
$ CareerSatisfaction          <fct> Extremely satisfied, Neither satisfied nor dissatisfied, Moderately satisfied, Slightly dissatisfied, Moderately satisfied, Slightly satisfied, Moderately sati...
$ HopeFiveYears               <fct> Working as a founder or co-founder of my own company, Working in a different or more specialized technical role than the one I'm in now, Working as a founder o...
$ JobSearchStatus             <fct> "Iâ\200\231m not actively looking, but I am open to new opportunities", "I am actively looking for a job", "Iâ\200\231m not actively looking, but I am open to ...
$ LastNewJob                  <fct> Less than a year ago, More than 4 years ago, Less than a year ago, Less than a year ago, Between 1 and 2 years ago, Between 2 and 4 years ago, Less than a year...
$ AssessJob1                  <int> 10, 1, NA, NA, 8, 8, 5, 6, 6, NA, NA, NA, NA, 6, 1, NA, 5, 9, NA, NA, 7, 3, 3, 10, NA, 1, 6, 7, 2, NA, 7, 3, 4, 10, NA, 5, 8, 10, NA, 7, NA, 3, 2, 5, 4, NA, 8,...
$ AssessJob2                  <int> 7, 7, NA, NA, 5, 5, 3, 5, 3, NA, NA, NA, NA, 9, 9, NA, 7, 4, NA, NA, 4, 4, 9, 9, NA, 7, 7, 10, 1, NA, 8, 1, 2, 8, NA, 4, 9, 9, NA, 2, NA, 5, 8, 8, 9, NA, 4, NA...
$ AssessJob3                  <int> 8, 10, NA, NA, 7, 4, 9, 4, 7, NA, NA, NA, NA, 2, 2, NA, 4, 10, NA, NA, 10, 6, 10, 7, NA, 6, 10, 8, 5, NA, 9, 10, 5, 6, NA, 2, 10, 8, NA, 1, NA, 9, 3, 3, 5, NA,...
$ AssessJob4                  <int> 1, 8, NA, NA, 1, 9, 4, 2, 4, NA, NA, NA, NA, 4, 10, NA, 8, 3, NA, NA, 2, 7, 6, 1, NA, 10, 4, 1, 7, NA, 4, 6, 3, 5, NA, 9, 3, 4, NA, 4, NA, 1, 5, 2, 7, NA, 2, N...
$ AssessJob5                  <int> 2, 2, NA, NA, 2, 1, 1, 7, 1, NA, NA, NA, NA, 3, 6, NA, 2, 1, NA, NA, 1, 1, 8, 3, NA, 9, 2, 4, 3, NA, 2, 8, 1, 1, NA, 1, 1, 1, NA, 3, NA, 7, 9, 4, 2, NA, 1, NA,...
$ AssessJob6                  <int> 5, 5, NA, NA, 6, 3, 8, 8, 5, NA, NA, NA, NA, 5, 3, NA, 6, 6, NA, NA, 5, 8, 7, 5, NA, 4, 5, 5, 4, NA, 6, 7, 8, 4, NA, 3, 6, 5, NA, 6, NA, 4, 6, 7, 10, NA, 3, NA...
$ AssessJob7                  <int> 3, 4, NA, NA, 4, 6, 2, 10, 10, NA, NA, NA, NA, 8, 4, NA, 9, 5, NA, NA, 3, 5, 1, 2, NA, 2, 3, 2, 10, NA, 1, 9, 9, 3, NA, 10, 4, 2, NA, 8, NA, 10, 7, 9, 6, NA, 7...
$ AssessJob8                  <int> 4, 3, NA, NA, 3, 2, 7, 1, 8, NA, NA, NA, NA, 7, 5, NA, 1, 2, NA, NA, 6, 2, 2, 6, NA, 3, 1, 3, 6, NA, 3, 2, 6, 2, NA, 8, 2, 3, NA, 5, NA, 2, 10, 6, 3, NA, 5, NA...
$ AssessJob9                  <int> 9, 6, NA, NA, 10, 10, 10, 9, 9, NA, NA, NA, NA, 10, 7, NA, 10, 7, NA, NA, 9, 9, 4, 4, NA, 8, 9, 6, 9, NA, 10, 5, 7, 7, NA, 7, 5, 7, NA, 10, NA, 8, 1, 10, 1, NA...
$ AssessJob10                 <int> 6, 9, NA, NA, 9, 7, 6, 3, 2, NA, NA, NA, NA, 1, 8, NA, 3, 8, NA, NA, 8, 10, 5, 8, NA, 5, 8, 9, 8, NA, 5, 4, 10, 9, NA, 6, 7, 6, NA, 9, NA, 6, 4, 1, 8, NA, 9, N...
$ AssessBenefits1             <int> NA, 1, NA, NA, 1, 1, 1, 1, 1, NA, NA, NA, NA, 5, 2, NA, 1, 1, NA, NA, 3, 2, 1, 1, NA, 1, 1, 1, 1, NA, 1, 3, 1, 1, NA, 2, 1, 1, NA, 1, NA, 7, NA, 1, 5, NA, 1, N...
$ AssessBenefits2             <int> NA, 5, NA, NA, 10, 3, 3, 3, 3, NA, NA, NA, NA, 2, 3, NA, 2, 8, NA, NA, 1, 4, 9, 8, NA, 10, 4, 5, 10, NA, 9, 10, 4, 9, NA, 3, 3, 6, NA, 2, NA, 11, NA, 4, 6, NA,...
$ AssessBenefits3             <int> NA, 3, NA, NA, 2, 4, 2, 5, 2, NA, NA, NA, NA, 1, 6, NA, 4, 9, NA, NA, 6, 1, 10, 3, NA, 6, 8, 3, 3, NA, 4, 4, 2, 2, NA, 1, 9, 10, NA, 4, NA, 1, NA, 2, 9, NA, 2,...
$ AssessBenefits4             <int> NA, 7, NA, NA, 4, 10, 9, 7, 9, NA, NA, NA, NA, 11, 11, NA, 10, 4, NA, NA, 4, 11, 5, 6, NA, 4, 5, 9, 6, NA, 5, 1, 10, 4, NA, 6, 11, 9, NA, 10, NA, 3, NA, 10, 2,...
$ AssessBenefits5             <int> NA, 10, NA, NA, 8, 9, 11, 6, 11, NA, NA, NA, NA, 6, 9, NA, 11, 11, NA, NA, 5, 7, 3, 10, NA, 3, 11, 10, 2, NA, 6, 6, 6, 11, NA, 7, 5, 7, NA, 8, NA, 9, NA, 8, 1,...
$ AssessBenefits6             <int> NA, 4, NA, NA, 3, 2, 4, 2, 5, NA, NA, NA, NA, 8, 8, NA, 5, 3, NA, NA, 8, 3, 11, 4, NA, 9, 7, 2, 4, NA, 11, 9, 3, 3, NA, 4, 7, 8, NA, 3, NA, 4, NA, 3, 3, NA, 4,...
$ AssessBenefits7             <int> NA, 11, NA, NA, 11, 6, 8, 11, 8, NA, NA, NA, NA, 10, 10, NA, 6, 5, NA, NA, 9, 8, 8, 9, NA, 11, 6, 7, 11, NA, 7, 11, 8, 10, NA, 9, 4, 5, NA, 9, NA, 10, NA, 7, 4...
$ AssessBenefits8             <int> NA, 9, NA, NA, 7, 5, 6, 9, 4, NA, NA, NA, NA, 4, 4, NA, 7, 6, NA, NA, 7, 5, 2, 5, NA, 7, 9, 8, 9, NA, 3, 5, 5, 8, NA, 10, 2, 4, NA, 6, NA, 6, NA, 6, 7, NA, 8, ...
$ AssessBenefits9             <int> NA, 6, NA, NA, 5, 11, 7, 4, 10, NA, NA, NA, NA, 7, 5, NA, 9, 10, NA, NA, 2, 9, 7, 7, NA, 5, 2, 11, 5, NA, 8, 2, 11, 6, NA, 5, 8, 11, NA, 11, NA, 2, NA, 11, 10,...
$ AssessBenefits10            <int> NA, 2, NA, NA, 9, 7, 10, 10, 7, NA, NA, NA, NA, 3, 7, NA, 8, 7, NA, NA, 11, 6, 6, 11, NA, 8, 10, 6, 8, NA, 10, 7, 9, 5, NA, 8, 10, 3, NA, 7, NA, 8, NA, 9, 11, ...
$ AssessBenefits11            <int> NA, 8, NA, NA, 6, 8, 5, 8, 6, NA, NA, NA, NA, 9, 1, NA, 3, 2, NA, NA, 10, 10, 4, 2, NA, 2, 3, 4, 7, NA, 2, 8, 7, 7, NA, 11, 6, 2, NA, 5, NA, 5, NA, 5, 8, NA, 6...
$ JobContactPriorities1       <int> 3, 3, NA, NA, 2, 4, 3, 1, 5, NA, NA, NA, NA, NA, 5, NA, NA, NA, NA, NA, 2, 2, NA, 4, NA, NA, 5, NA, NA, NA, 5, 2, NA, 3, NA, NA, NA, 4, NA, 1, NA, 2, NA, NA, N...
$ JobContactPriorities2       <int> 1, 1, NA, NA, 1, 2, 1, 3, 1, NA, NA, NA, NA, NA, 3, NA, NA, NA, NA, NA, 1, 1, NA, 1, NA, NA, 3, NA, NA, NA, 2, 1, NA, 1, NA, NA, NA, 1, NA, 2, NA, 1, NA, NA, N...
$ JobContactPriorities3       <int> 4, 5, NA, NA, 4, 5, 5, 2, 2, NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 4, 5, NA, 5, NA, NA, 4, NA, NA, NA, 4, 4, NA, 5, NA, NA, NA, 5, NA, 5, NA, 5, NA, NA, N...
$ JobContactPriorities4       <int> 2, 2, NA, NA, 5, 1, 4, 4, 3, NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, 3, 4, NA, 3, NA, NA, 2, NA, NA, NA, 1, 5, NA, 2, NA, NA, NA, 2, NA, 4, NA, 3, NA, NA, N...
$ JobContactPriorities5       <int> 5, 4, NA, NA, 3, 3, 2, 5, 4, NA, NA, NA, NA, NA, 4, NA, NA, NA, NA, NA, 5, 3, NA, 2, NA, NA, 1, NA, NA, NA, 3, 3, NA, 4, NA, NA, NA, 3, NA, 3, NA, 4, NA, NA, N...
$ JobEmailPriorities1         <int> 5, 1, NA, NA, 7, 2, 1, 2, 3, NA, NA, NA, NA, NA, 1, NA, NA, 7, NA, NA, 7, 2, NA, 6, NA, 1, 7, NA, NA, NA, 6, 6, NA, 1, NA, NA, NA, 5, NA, 7, NA, 4, 3, NA, NA, ...
$ JobEmailPriorities2         <int> 6, 3, NA, NA, 3, 6, 5, 6, 7, NA, NA, NA, NA, NA, 2, NA, NA, 6, NA, NA, 3, 1, NA, 7, NA, 5, 3, NA, NA, NA, 7, 5, NA, 7, NA, NA, NA, 3, NA, 2, NA, 3, 6, NA, NA, ...
$ JobEmailPriorities3         <int> 7, 4, NA, NA, 6, 7, 3, 1, 2, NA, NA, NA, NA, NA, 6, NA, NA, 1, NA, NA, 4, 3, NA, 2, NA, 4, 1, NA, NA, NA, 4, 7, NA, 4, NA, NA, NA, 6, NA, 1, NA, 2, 5, NA, NA, ...
$ JobEmailPriorities4         <int> 2, 5, NA, NA, 2, 3, 4, 3, 4, NA, NA, NA, NA, NA, 7, NA, NA, 5, NA, NA, 5, 5, NA, 3, NA, 2, 4, NA, NA, NA, 3, 4, NA, 3, NA, NA, NA, 1, NA, 5, NA, 1, 7, NA, NA, ...
$ JobEmailPriorities5         <int> 1, 2, NA, NA, 1, 1, 2, 7, 1, NA, NA, NA, NA, NA, 3, NA, NA, 3, NA, NA, 2, 4, NA, 1, NA, 7, 5, NA, NA, NA, 1, 3, NA, 2, NA, NA, NA, 2, NA, 6, NA, 7, 1, NA, NA, ...
$ JobEmailPriorities6         <int> 4, 6, NA, NA, 4, 5, 6, 5, 6, NA, NA, NA, NA, NA, 4, NA, NA, 4, NA, NA, 1, 7, NA, 5, NA, 6, 6, NA, NA, NA, 2, 1, NA, 5, NA, NA, NA, 4, NA, 3, NA, 6, 4, NA, NA, ...
$ JobEmailPriorities7         <int> 3, 7, NA, NA, 5, 4, 7, 4, 5, NA, NA, NA, NA, NA, 5, NA, NA, 2, NA, NA, 6, 6, NA, 4, NA, 3, 2, NA, NA, NA, 5, 2, NA, 6, NA, NA, NA, 7, NA, 4, NA, 5, 2, NA, NA, ...
$ UpdateCV                    <fct> My job status or other personal status changed, I saw an employer’s advertisement, NA, A recruiter contacted me, My job status or other personal status chang...
$ Currency                    <fct> NA, British pounds sterling (£), NA, U.S. dollars ($), South African rands (R), British pounds sterling (£), U.S. dollars ($), NA, U.S. dollars ($), NA, NA, ...
$ Salary                      <fct> NA, 51000, NA, NA, 260000, 30000, 120000, NA, 250000, NA, NA, NA, NA, NA, 0, NA, NA, 32000, NA, NA, 120000, NA, 25, 75000, 700000, 3500, 582000, 75000, NA, NA,...
$ SalaryType                  <fct> Monthly, Yearly, NA, NA, Yearly, NA, Yearly, NA, Yearly, NA, NA, NA, NA, NA, Monthly, NA, NA, Monthly, Monthly, NA, Yearly, Monthly, Monthly, Yearly, Yearly, M...
$ ConvertedSalary             <dbl> NA, 70841, NA, NA, 21426, 41671, 120000, NA, 250000, NA, NA, NA, NA, NA, 0, NA, NA, 47904, NA, NA, 95968, NA, 420, 75000, 10958, 51408, 72611, 900000, NA, NA, ...
$ CurrencySymbol              <fct> KES, GBP, NA, NA, ZAR, GBP, USD, NA, USD, NA, NA, NA, NA, NA, EUR, NA, NA, SEK, NA, NA, AUD, USD, GBP, USD, INR, EUR, SEK, USD, NA, NA, PLN, SEK, USD, USD, NA,...
$ CommunicationTools          <fct> "Slack", "Confluence;Office / productivity suite (Microsoft Office, Google Suite, etc.);Slack;Other wiki tool (Github, Google Sites, proprietary software, etc....
$ TimeFullyProductive         <fct> One to three months, One to three months, NA, Three to six months, Three to six months, Less than a month, Six to nine months, One to three months, Three to si...
$ EducationTypes              <fct> "Taught yourself a new language, framework, or tool without taking a formal course;Participated in a hackathon", "Taught yourself a new language, framework, or...
$ SelfTaughtTypes             <fct> "The official documentation and/or standards for the technology;A book or e-book from Oâ\200\231Reilly, Apress, or a similar publisher;Questions & answers on S...
$ TimeAfterBootcamp           <fct> NA, NA, NA, NA, NA, NA, NA, Immediately after graduating, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, I already had a full-time job as a develo...
$ HackathonReasons            <fct> "To build my professional network", NA, NA, NA, NA, "To improve my general technical skills or programming ability;To improve my knowledge of a specific progra...
$ AgreeDisagree1              <fct> Strongly agree, Agree, NA, Disagree, Strongly agree, Disagree, Disagree, Strongly agree, Strongly agree, NA, NA, NA, NA, NA, Disagree, NA, NA, Neither Agree no...
$ AgreeDisagree2              <fct> Strongly agree, Agree, NA, Disagree, Agree, Neither Agree nor Disagree, Agree, Strongly disagree, Strongly disagree, NA, NA, NA, NA, NA, Strongly disagree, NA,...
$ AgreeDisagree3              <fct> Neither Agree nor Disagree, Neither Agree nor Disagree, NA, Strongly disagree, Strongly disagree, Strongly disagree, Strongly disagree, Neither Agree nor Disag...
$ LanguageWorkedWith          <fct> JavaScript;Python;HTML;CSS, JavaScript;Python;Bash/Shell, NA, C#;JavaScript;SQL;TypeScript;HTML;CSS;Bash/Shell, C;C++;Java;Matlab;R;SQL;Bash/Shell, Java;JavaSc...
$ LanguageDesireNextYear      <fct> JavaScript;Python;HTML;CSS, Go;Python, NA, C#;JavaScript;SQL;TypeScript;HTML;CSS;Bash/Shell, Assembly;C;C++;Matlab;SQL;Bash/Shell, C#;Go;Java;JavaScript;Python...
$ DatabaseWorkedWith          <fct> "Redis;SQL Server;MySQL;PostgreSQL;Amazon RDS/Aurora;Microsoft Azure (Tables, CosmosDB, SQL, etc)", "Redis;PostgreSQL;Memcached", NA, "SQL Server;Microsoft Azu...
$ DatabaseDesireNextYear      <fct> "Redis;SQL Server;MySQL;PostgreSQL;Amazon RDS/Aurora;Microsoft Azure (Tables, CosmosDB, SQL, etc)", "PostgreSQL", NA, "SQL Server;Microsoft Azure (Tables, Cosm...
$ PlatformWorkedWith          <fct> AWS;Azure;Linux;Firebase, Linux, NA, Azure, Arduino;Windows Desktop or Server, Linux, Linux, Azure;Heroku, Amazon Echo;AWS;iOS;Linux;Mac OS;Serverless, NA, NA,...
$ PlatformDesireNextYear      <fct> AWS;Azure;Linux;Firebase, Linux, NA, Azure, Arduino;Windows Desktop or Server, Linux, Linux, Amazon Echo;Android;Apple Watch or Apple TV;AWS;Google Cloud Platf...
$ FrameworkWorkedWith         <fct> Django;React, Django, NA, NA, NA, Angular;Node.js, Node.js;React, Angular;Node.js, Hadoop;Node.js;React;Spark, NA, NA, NA, NA, Spring, NA, NA, NA, .NET Core, A...
$ FrameworkDesireNextYear     <fct> Django;React, React, NA, Angular;.NET Core;React, NA, Node.js, React;TensorFlow, .NET Core;Django, NA, NA, NA, NA, NA, Hadoop;Spark;Spring, NA, NA, NA, .NET Co...
$ IDE                         <fct> Komodo;Vim;Visual Studio Code, IPython / Jupyter;Sublime Text;Vim, NA, Visual Studio;Visual Studio Code, Notepad++;Visual Studio;Visual Studio Code, IntelliJ;P...
$ OperatingSystem             <fct> Linux-based, Linux-based, NA, Windows, Windows, Linux-based, MacOS, Windows, MacOS, NA, NA, NA, NA, Linux-based, Windows, NA, NA, Windows, Windows, NA, MacOS, ...
$ NumberMonitors              <fct> 1, 2, NA, 2, 2, 2, 2, 1, 1, NA, NA, NA, NA, More than 4, 2, NA, NA, 1, More than 4, NA, 1, 3, 2, 3, 1, 2, 2, 2, NA, 2, 2, 2, 2, 2, 2, 2, 1, 2, NA, 2, 1, 1, 1, ...
$ Methodology                 <fct> Agile;Scrum, NA, NA, Agile;Kanban;Scrum, Evidence-based software engineering;Formal standard such as ISO 9001 or IEEE 12207 (aka “waterfall” methodologies)...
$ VersionControl              <fct> Git, Git;Subversion, NA, Git, Zip file back-ups, Git, Git, Git, Git, NA, NA, NA, NA, Git, Copying and pasting files to network shares, NA, NA, Git, Git, NA, Gi...
$ CheckInCode                 <fct> Multiple times per day, A few times per week, NA, Multiple times per day, Weekly or a few times per month, A few times per week, Multiple times per day, Multip...
$ AdBlocker                   <fct> Yes, Yes, NA, Yes, No, Yes, Yes, Yes, No, NA, NA, NA, NA, Yes, No, NA, NA, Yes, I'm not sure/I don't know, NA, Yes, No, Yes, No, No, Yes, Yes, Yes, NA, Yes, Ye...
$ AdBlockerDisable            <fct> No, Yes, NA, Yes, NA, Yes, Yes, No, NA, NA, NA, NA, NA, No, NA, NA, NA, Yes, NA, NA, Yes, NA, No, NA, NA, No, Yes, Yes, NA, No, Yes, Yes, NA, Yes, Yes, No, I'm...
$ AdBlockerReasons            <fct> NA, The website I was visiting asked me to disable it, NA, The ad-blocking software was causing display issues on a website, NA, I wanted to support the websit...
$ AdsAgreeDisagree1           <fct> Strongly agree, Somewhat agree, NA, Neither agree nor disagree, Somewhat agree, Somewhat agree, Somewhat disagree, Strongly agree, Neither agree nor disagree, ...
$ AdsAgreeDisagree2           <fct> Strongly agree, Neither agree nor disagree, NA, Somewhat agree, Somewhat agree, Somewhat agree, Neither agree nor disagree, Neither agree nor disagree, Somewha...
$ AdsAgreeDisagree3           <fct> Strongly agree, Neither agree nor disagree, NA, Somewhat agree, Somewhat disagree, Somewhat disagree, Somewhat disagree, Strongly disagree, Neither agree nor d...
$ AdsActions                  <fct> Saw an online advertisement and then researched it (without clicking on the ad);Stopped going to a website because of their advertising, NA, NA, Stopped going ...
$ AdsPriorities1              <int> 1, 3, NA, NA, 2, 1, 1, NA, 1, NA, NA, NA, NA, NA, 4, NA, NA, 3, NA, NA, 2, 1, 1, 1, NA, NA, NA, 3, NA, NA, 1, 3, 1, 5, 1, 5, 2, 2, NA, 1, 1, 5, 1, 1, 5, 5, 4, ...
$ AdsPriorities2              <int> 5, 5, NA, NA, 3, 3, 4, NA, 3, NA, NA, NA, NA, NA, 5, NA, NA, 2, NA, NA, 3, 3, 6, 7, NA, NA, NA, 1, NA, NA, 2, 4, 6, 3, 4, 2, 5, 3, NA, 3, 6, 3, 7, 5, 6, 2, 5, ...
$ AdsPriorities3              <int> 4, 1, NA, NA, 4, 4, 2, NA, 5, NA, NA, NA, NA, NA, 6, NA, NA, 4, NA, NA, 1, 2, 2, 3, NA, NA, NA, 2, NA, NA, 3, 2, 3, 6, 2, 3, 6, 1, NA, 2, 3, 1, 5, 4, 1, 4, 2, ...
$ AdsPriorities4              <int> 7, 4, NA, NA, 6, 2, 5, NA, 4, NA, NA, NA, NA, NA, 2, NA, NA, 7, NA, NA, 7, 4, 3, 2, NA, NA, NA, 7, NA, NA, 5, 1, 2, 2, 5, 6, 1, 6, NA, 4, 4, 6, 6, 3, 7, 1, 3, ...
$ AdsPriorities5              <int> 2, 6, NA, NA, 1, 7, 3, NA, 2, NA, NA, NA, NA, NA, 1, NA, NA, 5, NA, NA, 6, 7, 5, 5, NA, NA, NA, 6, NA, NA, 7, 6, 7, 4, 6, 1, 4, 5, NA, 7, 2, 2, 3, 2, 4, 6, 6, ...
$ AdsPriorities6              <int> 6, 7, NA, NA, 7, 5, 7, NA, 7, NA, NA, NA, NA, NA, 7, NA, NA, 6, NA, NA, 4, 5, 4, 4, NA, NA, NA, 5, NA, NA, 4, 7, 5, 1, 7, 4, 3, 7, NA, 6, 7, 7, 2, 6, 2, 7, 1, ...
$ AdsPriorities7              <int> 3, 2, NA, NA, 5, 6, 6, NA, 6, NA, NA, NA, NA, NA, 3, NA, NA, 1, NA, NA, 5, 6, 7, 6, NA, NA, NA, 4, NA, NA, 6, 5, 4, 7, 3, 7, 7, 4, NA, 5, 5, 4, 4, 7, 3, 3, 7, ...
$ AIDangerous                 <fct> Artificial intelligence surpassing human intelligence ("the singularity"), Increasing automation of jobs, NA, Artificial intelligence surpassing human intellig...
$ AIInteresting               <fct> Algorithms making important decisions, Increasing automation of jobs, NA, Artificial intelligence surpassing human intelligence ("the singularity"), Algorithms...
$ AIResponsible               <fct> The developers or the people creating the AI, The developers or the people creating the AI, NA, A governmental or other regulatory body, The developers or the ...
$ AIFuture                    <fct> "I'm excited about the possibilities more than worried about the dangers.", "I'm excited about the possibilities more than worried about the dangers.", NA, "I ...
$ EthicsChoice                <fct> No, Depends on what it is, NA, No, No, Depends on what it is, Depends on what it is, Depends on what it is, No, NA, NA, NA, NA, Depends on what it is, No, NA, ...
$ EthicsReport                <fct> "Yes, and publicly", "Depends on what it is", NA, "Yes, but only within the company", "Yes, but only within the company", "Depends on what it is", "Yes, but on...
$ EthicsResponsible           <fct> Upper management at the company/organization, Upper management at the company/organization, NA, Upper management at the company/organization, Upper management ...
$ EthicalImplications         <fct> Yes, Yes, NA, Yes, Yes, Unsure / I don't know, Yes, Yes, Yes, NA, NA, NA, NA, Yes, Yes, NA, NA, Yes, No, NA, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Unsure / I don'...
$ StackOverflowRecommend      <fct> 10 (Very Likely), 10 (Very Likely), NA, 10 (Very Likely), 10 (Very Likely), 7, 10 (Very Likely), 10 (Very Likely), 7, NA, NA, 7, 10 (Very Likely), 10 (Very Lik...
$ StackOverflowVisit          <fct> Multiple times per day, A few times per month or weekly, NA, A few times per week, Daily or almost daily, A few times per month or weekly, Multiple times per d...
$ StackOverflowHasAccount     <fct> Yes, Yes, NA, Yes, Yes, Yes, Yes, Yes, Yes, NA, NA, Yes, I'm not sure / I can't remember, Yes, Yes, No, Yes, Yes, I'm not sure / I can't remember, Yes, Yes, Ye...
$ StackOverflowParticipate    <fct> I have never participated in Q&A on Stack Overflow, A few times per month or weekly, NA, A few times per month or weekly, Less than once per month or monthly, ...
$ StackOverflowJobs           <fct> "No, I knew that Stack Overflow had a jobs board but have never used or visited it", "Yes", NA, "Yes", "No, I knew that Stack Overflow had a jobs board but hav...
$ StackOverflowDevStory       <fct> "Yes", "No, I have one but it's out of date", NA, "No, I have one but it's out of date", "No, I know what it is but I don't have one", "No, I have one but it's...
$ StackOverflowJobsRecommend  <fct> NA, 7, NA, 8, NA, 8, 7, NA, 7, NA, NA, NA, NA, 10 (Very Likely), NA, NA, NA, 6, 10 (Very Likely), NA, 6, 7, NA, 5, 10 (Very Likely), 9, 5, 1, NA, NA, 5, 7, 10 ...
$ StackOverflowConsiderMember <fct> Yes, Yes, NA, Yes, Yes, No, No, Yes, No, NA, NA, NA, Yes, Yes, No, No, Yes, No, I'm not sure, No, No, Yes, I'm not sure, No, Yes, Yes, No, Yes, NA, I'm not sur...
$ HypotheticalTools1          <fct> Extremely interested, A little bit interested, NA, Somewhat interested, Extremely interested, A little bit interested, Very interested, Very interested, Not at...
$ HypotheticalTools2          <fct> Extremely interested, A little bit interested, NA, Somewhat interested, Extremely interested, Not at all interested, A little bit interested, Very interested, ...
$ HypotheticalTools3          <fct> Extremely interested, A little bit interested, NA, Somewhat interested, Extremely interested, Very interested, Extremely interested, Very interested, Not at al...
$ HypotheticalTools4          <fct> Extremely interested, A little bit interested, NA, Somewhat interested, Extremely interested, Very interested, Very interested, A little bit interested, Not at...
$ HypotheticalTools5          <fct> Extremely interested, A little bit interested, NA, Somewhat interested, Extremely interested, Extremely interested, Very interested, Extremely interested, Not ...
$ WakeTime                    <fct> Between 5:00 - 6:00 AM, Between 6:01 - 7:00 AM, NA, Between 6:01 - 7:00 AM, Before 5:00 AM, Between 7:01 - 8:00 AM, Between 9:01 - 10:00 AM, I do not have a se...
$ HoursComputer               <fct> 9 - 12 hours, 5 - 8 hours, NA, 9 - 12 hours, Over 12 hours, 9 - 12 hours, Over 12 hours, Over 12 hours, 9 - 12 hours, NA, NA, NA, NA, 5 - 8 hours, 9 - 12 hours...
$ HoursOutside                <fct> 1 - 2 hours, 30 - 59 minutes, NA, Less than 30 minutes, 1 - 2 hours, 30 - 59 minutes, Less than 30 minutes, 1 - 2 hours, Less than 30 minutes, NA, NA, NA, NA, ...
$ SkipMeals                   <fct> Never, Never, NA, 3 - 4 times per week, Never, 1 - 2 times per week, 1 - 2 times per week, Daily or almost every day, 1 - 2 times per week, NA, NA, NA, NA, Nev...
$ ErgonomicDevices            <fct> Standing desk, Ergonomic keyboard or mouse, NA, NA, NA, NA, NA, NA, Standing desk;Fatigue-relieving floor mat, NA, NA, NA, NA, Ergonomic keyboard or mouse, NA,...
$ Exercise                    <fct> 3 - 4 times per week, Daily or almost every day, NA, I don't typically exercise, 3 - 4 times per week, 1 - 2 times per week, I don't typically exercise, 1 - 2 ...
$ Gender                      <fct> "Male", "Male", NA, "Male", "Male", "Male", "Male", "Female", "Male", NA, NA, NA, NA, NA, "Male", NA, NA, "Male", "Female", NA, "Male", "Male", "Male", "Female...
$ SexualOrientation           <fct> Straight or heterosexual, Straight or heterosexual, NA, Straight or heterosexual, Straight or heterosexual, Straight or heterosexual, Straight or heterosexual,...
$ EducationParents            <fct> "Bachelorâ\200\231s degree (BA, BS, B.Eng., etc.)", "Bachelorâ\200\231s degree (BA, BS, B.Eng., etc.)", NA, "Some college/university study without earning a de...
$ RaceEthnicity               <fct> "Black or of African descent", "White or of European descent", NA, "White or of European descent", "White or of European descent", "White or of European descen...
$ Age                         <fct> 25 - 34 years old, 35 - 44 years old, NA, 35 - 44 years old, 18 - 24 years old, 18 - 24 years old, 18 - 24 years old, 25 - 34 years old, 35 - 44 years old, NA,...
$ Dependents                  <fct> Yes, Yes, NA, No, Yes, No, No, No, Yes, NA, NA, NA, NA, NA, No, NA, NA, Yes, NA, NA, Yes, Yes, No, Yes, No, Yes, Yes, No, NA, Yes, No, No, No, No, Yes, Yes, No...
$ MilitaryUS                  <fct> NA, NA, NA, No, NA, NA, No, NA, No, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, No, NA, No, NA, NA, NA, No, NA, NA, NA, NA, No, No, NA, No, NA, NA, NA, Yes...
$ SurveyTooLong               <fct> The survey was an appropriate length, The survey was an appropriate length, NA, The survey was an appropriate length, The survey was an appropriate length, The...
$ SurveyEasy                  <fct> Very easy, Somewhat easy, NA, Somewhat easy, Somewhat easy, Somewhat easy, Somewhat easy, Somewhat difficult, Very easy, NA, NA, NA, NA, NA, Neither easy nor d...

From the glimpse, we can see that there are some null values in some questions. This is due to the fact that most of the questions are optional in the survey. For the sake of exploration of this dataset, we will not be considering null values but it would be interesting to explore why a few questions have been answered null by the respondents.

Part I : General exploration of survey results

Let’s see which countries have the maximum respondents of the survey.

survey %>% 
  group_by(Country) %>%
  count() %>%
  arrange(desc(n)) %>%
  head(20) %>%
  hchart('treemap',hcaes(x=Country, value=n, color=n)) %>%
  hc_colorAxis(stops=color_stops(colors=plasma(10))) %>%
  hc_title(text="Top 20 Countries of respondents of survey")

As we can see from the above tree map, the country with the maximum number of respondents come from United States with India at second position while Germany, United Kingdom and Canada make up the top 5. Let us also take a look at the percentage distribution of respondents

size=nrow(survey)
survey %>% 
  group_by(Country) %>%
  count() %>%
  arrange(desc(n)) %>%
  head(20) %>%
  hchart('bar',hcaes(x=Country, y=round((n/size)*100,2))) %>%
  hc_colorAxis(stops=color_stops(colors=plasma(10))) %>%
  hc_title(text="Top 20 Countries of respondents of survey") %>%
  hc_yAxis(title=list(text="Percentage of respondents"),labels = list(format = "{value}%")) %>%
  hc_add_theme(hc_theme_tufte())

From the bar chart above, we can see that : 20.54% of respondents are from the United States 13.88% of respondents are from India Germany(6.53%),United Kingdom(6.29%) and Canada(3.43%) have the next 3 highest respondents.

survey %>%
  group_by(Country) %>%
  count() -> country
  country$Country <- as.character(country$Country)
  country[country=="United States"] <- "United States of America"
  country[country=="Russian Federation"] <- "Russia"
  highchart() %>%
    hc_add_series_map(worldgeojson,country,value='n',joinBy=c('name','Country')) %>%
    hc_colorAxis(stops=color_stops(colors=viridis(10))) %>%
    hc_title(text="Countries by no. of respondents") %>%
    hc_add_theme(hc_theme_tufte())
NA

The above map is a better visualization of all the respondents by country.

Now, let us look at how many respondents take up coding as a hobby.

survey %>%
  group_by(Hobby) %>%
  count() %>%
  plot_ly(type="pie",
          labels=~Hobby,
          values=~n,
          textposition="inside",
          textinfo='label+percent+value',
          showlegend=FALSE,
          marker=list(colors = viridis(2))
  )%>%
          layout(title="Is coding a hobby for respondents?")
NA

From the above piechart, we can see that more than 80% of the respondents take up coding as a hobby.

survey %>%
  group_by(OpenSource) %>%
  count() %>%
  plot_ly(type="pie",
          labels=~OpenSource,
          values=~n,
          textposition="inside",
          textinfo='label+percent+value',
          showlegend=FALSE,
          marker=list(colors = viridis(2))
  )%>%
          layout(title="Do respondents contribute to OpenSource Projets?")

From the above piechart, we can see that around 56% of respondents contribute to open source projects.

Let’s take a look at the gender of respondents.

  S <- sum(is.na(survey$Gender))
  S
[1] 34386
  round((S/size)*100,2)
[1] 34.78

We see that almost 34386(34.78%) respondents have not disclosed their gender in the survey. It would be interesting to know the reason behind this.

survey %>% 
  filter(!is.na(Gender)) %>%
  group_by(Gender) %>%
  count() %>%
  plot_ly(type="pie",
          labels=~Gender,
          values=~n,
          textposition="inside",
          textinfo='label+percent',
          showlegend=FALSE,
          marker=list(colors = viridis(10))
  ) %>%
  layout(title="Gender of respondents")

The results are very shocking. We can see that 92.2% respondents who gave their gender are male, 6.24% of the respondents are female while the rest are transgender, non-binary or gender non-conforming. The results maybe misleading due to the fact that 34.78% of the respondents have not disclosed their gender. The reasons for this is not known, but the above chart shows us that there exists a huge gender gap in the StackOverflow Community. Now, let’s take a look at whether the respondents are students and their current employment status.

survey %>%
  filter(!is.na(Student)) %>%
  group_by(Student)%>%
  count() %>%
  hchart("pie",hcaes(x=Student,y=round((n/size)*100,2))) %>%
  hc_add_theme(hc_theme_ffx()) %>%
  hc_title(text="Are the respondents students?",align="center",style = list(fontWeight="bold", fontSize="30px"))

From the above pie chart, we can see that more that 71.21% of the respondents are not students, 18.61% are full time students while 6.18 are part-time students.

survey %>%
  filter(!is.na(Employment)) %>%
  group_by(Employment)%>%
  count() %>%
  hchart("pie",hcaes(x=Employment,y=round((n/size)*100,2))) %>%
  hc_add_theme(hc_theme_ffx()) %>%
  hc_title(text="Employment status of the respondents",align="center",style = list(fontWeight="bold", fontSize="30px"))

From, the above pie chart, we can see that 71.31% are employed full time, 5.44% are employed part time, 9.39% are self-employed or freelancers while 20.05% are not employed. It is refreshing to see that full time employees take time to contribute to the StackOverflow Community.

Now, let us take a look at the education of the respondents.

survey %>%
  filter(!is.na(FormalEducation)) %>%
  group_by(FormalEducation) %>%
  count() %>%
  hchart("bar",hcaes(x=FormalEducation,y=n)) %>%
  hc_title(text="Highest Level of Formal Education of respondents",style=list(fontWeight="bold")) %>%
  hc_yAxis(title=list(text="No of respondents",style=list(fontWeight="bold"))) %>%
  hc_xAxis(title=list(text="Highest Level of Fromal Education",style=list(fontWeight="bold"))) %>%
  hc_add_theme(hc_theme_ft()) %>%
  hc_colors("black")

We can see that majority of respondents have received a bachelor’s degree or a master’s degree. Only a very few students have not completed any formal education.

Let’s take a look at what the respondents have majored in during their undergraduation.

S <- sum(is.na(survey$UndergradMajor))
S
[1] 19819
round((S/size)*100,2)
[1] 20.05

As we can see above, around 20% of respondents have not disclosed their undergrad major. This can be explained by the fact that almost 20% of students have either not received an undergrad degree as they have only completed their schooling, haven’t had any formal education or have studied in college without earning a degree. This can be seen in the previous barplot.

survey %>%
  filter(!is.na(UndergradMajor)) %>%
  group_by(UndergradMajor) %>%
  count() %>%
  hchart("bar",hcaes(x=UndergradMajor,y=round((n/size)*100,2))) %>%
  hc_title(text="Undergraduation Majors of respondents",style=list(fontWeight="bold")) %>%
  hc_yAxis(title=list(text="Percent of respondents",style=list(fontWeight="bold")),labels = list(format = "{value}%")) %>%
  hc_xAxis(title=list(text="Major",style=list(fontWeight="bold"))) %>%
  hc_add_theme(hc_theme_ft()) %>%
  hc_colors("purple") 

The results are obvious as about 50.92% of respondents have a major in Computer Science stream, 7.03% are from another engineering discipline, 6.58% are from the IT stream.

Now that we’ve generally explored a few responses from the survey, let us try to find a few relationships between these responses

survey %>%
  count(Hobby,OpenSource) %>%
  hchart("column",hcaes(x=Hobby,y=n,group=OpenSource)) %>%
  hc_title(text="Contribution to OpenSource Projects by Coding as a Hobby",style=list(fontWeight="bold")) %>%
  hc_yAxis(title=list(text="No. of respondents",style=list(fontWeight="bold"))) %>%
  hc_xAxis(title=list(style=list(fontWeight="bold")))

It’s pretty clear that people who code as a hobby tend to contribute more to opensource projects.

Let’s first look at whether respondents code as a hobby and contribute to open source according to their student and employment status

survey %>% 
  filter(!is.na(Student)) %>%
  count(Hobby,Student) %>%
  hchart("bar",hcaes(x=Hobby,y=n,group=Student)) %>%
  hc_title(text="Coding as a hobby by Student Status",style=list(fontWeight="bold")) %>%
  hc_yAxis(title=list(text="No. of respondents",style=list(fontWeight="bold"))) %>%
  hc_xAxis(title=list(style=list(fontWeight="bold"))) %>%
  hc_add_theme(hc_theme_darkunica())

It is good to see that more number of students are coding as a hobby rather that studying it for the sake of university.

survey %>% 
  filter(!is.na(Student)) %>%
  count(OpenSource,Student) %>%
  hchart("bar",hcaes(x=OpenSource,y=n,group=Student)) %>%
  hc_title(text="Contribution to OpenSource Projects by Sudent Status",style=list(fontWeight="bold")) %>%
  hc_xAxis(title=list(text="No. of respondents",style=list(fontWeight="bold"))) %>%
  hc_yAxis(title=list(style=list(fontWeight="bold"))) %>%
  hc_add_theme(hc_theme_darkunica())

It can be seen that most people who are not students contribute to open source projects, while full time students contribute to open source projects the least. This is worrying to see as contributing to open source projects may be a great way to learn for students.

survey %>% 
  filter(!is.na(Employment)) %>%
  count(OpenSource,Employment) %>%
  hchart("column",hcaes(x=Employment,y=n,group=OpenSource)) %>%
  hc_title(text="Contribution to OpenSource Projects by Employment Status",style=list(fontWeight="bold")) %>%
  hc_xAxis(title=list(text="No. of respondents",style=list(fontWeight="bold"))) %>%
  hc_yAxis(title=list(style=list(fontWeight="bold"))) %>%
  hc_add_theme(hc_theme_flat())

The results are pretty clear that respondents who are employed full time do not contribute more to Open Source Projects while Freelancers and Independent contractors tend to contribute more to Open Source Projects. However, the results are puzzling that respondents who are employed part time or not employed do not contribute more to Open Source Projects.

Next, Let us take a look at the current Employment Status vs where respondents hope to be in five years.

survey %>% 
  filter(!is.na(Employment)) %>%
  filter(!is.na(HopeFiveYears)) %>%
  count(Employment,HopeFiveYears) %>%
  hchart("bar",hcaes(x=HopeFiveYears,y=n,group=Employment)) %>%
  hc_title(text="Current Employment vs Hope in Five Years",style=list(fontWeight="bold")) %>%
  hc_yAxis(title=list(text="No. of respondents",style=list(fontWeight="bold"))) %>%
  hc_xAxis(title=list(text="Hope in Five Years",style=list(fontWeight="bold"))) %>%
  hc_add_theme(hc_theme_google())

Inferences from the above chart: 1. Most people who are currently employed full time or part time hope to either work in a different/more specialized role in five years or want to find their own company. 2. Most people who are self-employed or independent contractors hope to be a founder/co-founder of their own company or expect to be doing the same work in five years, which shows that people who are self-employed or independent contractors are more satisfied with their job. 3. It is surprising that people who are currently not looking for work hope to be working in five years.

Let us look at the job-satisfaction according to current employment Status

survey %>% 
  filter(!is.na(Employment)) %>%
  filter(!is.na(JobSatisfaction)) %>%
  count(Employment,JobSatisfaction) %>%
  hchart("area",hcaes(x=JobSatisfaction,y=n,group=Employment)) %>%
  hc_title(text="Current Employment vs Job Satisfaction",style=list(fontWeight="bold")) %>%
  hc_yAxis(title=list(text="No. of respondents",style=list(fontWeight="bold"))) %>%
  hc_xAxis(title=list(text="Job Satisfaction",style=list(fontWeight="bold"))) %>%
  hc_add_theme(hc_theme_flat())

From the above area chart, we can see that majority of the respondents are either extremely or moderately satisfied with their jobs, while only a very little percentage of respondents are extremely dissatisfied with their job.

survey %>% 
  filter(!is.na(HopeFiveYears)) %>%
  filter(!is.na(JobSatisfaction)) %>%
  count(HopeFiveYears,JobSatisfaction) %>%
  hchart("heatmap",hcaes(x=JobSatisfaction,y=HopeFiveYears,value=n)) %>%
  hc_title(text="Hope in Five Years vs Job Satisfaction",style=list(fontWeight="bold")) %>%
  hc_yAxis(title=list(text="Hope in Five years",style=list(fontWeight="bold"))) %>%
  hc_xAxis(title=list(text="Job Satisfaction",style=list(fontWeight="bold"))) %>%
  hc_add_theme(hc_theme_google()) 

The above heat map shows us that most people who are currently satisfied with their jobs expect to be in a higher role or start their own companies.

Part II: Developer Types, Years spent coding, Preferred Languages,IDEs, Frameworks and Company Size.

Let’s take a look at the type of Developers who took part in the survey

survey %>%
  filter(!is.na(DevType)) %>%
  select(DevType)%>%
  mutate(DevType=str_split(DevType,";")) %>%
  unnest(DevType) %>%
  group_by(DevType) %>%
  count() %>%
  arrange(desc(n))->t
t$n<- round((t$n/size)*100,2)
highchart() %>%
  hc_add_series(t,type = "bar", hcaes(x ="DevType", y = "n"), dataLabels = list(enabled = TRUE)) %>%
  hc_legend(enabled=FALSE) %>%
  hc_title(text="Developer Types of Respondents") %>%
  hc_xAxis(categories=t$DevType) %>% 
  hc_yAxis(title=list(text="Percentage of Respondents")) %>%
  hc_add_theme(hc_theme_tufte()) %>%
  hc_colors("orange")

We can see that a staggering 53.92% of respondents are Back-end Developers and 44.87% of respondents are Full-Stack Developers, whereas Front-end developers are third most with 35.23%. While Data Scientists and Data analysts are considered the hottest prospect of jobs, it is a bit surprising to see that only 7.17% and 7.65% of them have taken the survey.

Let’s take a look at how many years the respondents have spent coding.

survey %>%
  filter(!is.na(YearsCoding)) %>%
  group_by(YearsCoding) %>%
  count() %>%
  arrange(desc(n))->t
highchart() %>%
  hc_add_series(t,type = "column", hcaes(x ="YearsCoding", y = "n"), dataLabels = list(enabled = TRUE)) %>%
  hc_legend(enabled=FALSE) %>%
  hc_title(text="How many years have respondents spent coding?") %>%
  hc_xAxis(title=list(text="Years"),categories=t$YearsCoding) %>% 
  hc_yAxis(title=list(text="No. of respondents")) %>%
  hc_add_theme(hc_theme_tufte()) %>%
  hc_colors("blue")

Most of the respondents have spent coding for 3-5 years while the second and third-most are respondents who have spent coding for 6-8 years and 9-11 years. What is most surprising to see is that more than 8000 respondents(~9%) have coded for more than 20 years and still contribute to the StackOverflow Community.

survey %>%
  filter(!is.na(YearsCodingProf)) %>%
  group_by(YearsCodingProf) %>%
  count() %>%
  arrange(desc(n))->t
highchart() %>%
  hc_add_series(t,type = "column", hcaes(x ="YearsCodingProf", y = "n"), dataLabels = list(enabled = TRUE)) %>%
  hc_legend(enabled=FALSE) %>%
  hc_title(text="How many years have respondents spent coding professionally?") %>%
  hc_xAxis(title=list(text="Years"),categories=t$YearsCodingProf) %>% 
  hc_yAxis(title=list(text="No. of respondents")) %>%
  hc_add_theme(hc_theme_tufte()) %>%
  hc_colors("blue")

While most respondents have coded for 3-5 years and 6-8 years as seen in the previous plot, a majority of them have coded professionally for only less than 5 years. This can indicate one of the following things:

  1. A lot of people of start coding during their college years and continue to code professionally.
  2. A lot of people start coding only when they get a job. Let us take a look at the following plot to understand more.
survey %>%
  count(YearsCoding,YearsCodingProf) %>%
  hchart("heatmap",hcaes(x=YearsCoding,y=YearsCodingProf,value=n)) %>%
  hc_title(text="Years Coded vs Years Coding Professionally") %>%
  hc_xAxis(title=list(text="Years Coded")) %>% 
  hc_yAxis(title=list(text="Years Coding Professionally"))

As we can see, 1. Most people who have coded for 0-2 years have coded only professionally. 2. Majority of people who have coded for 3-5 have also coded professionally for 3-5 years. 3. A lot of people who have coded for 6-8 years have also coded professionally for 6-8 years. All of this indicates that a majority of people have only ever coded professionally which means they have begun coding only after getting or starting a job.

We can also see the next majority of people who have coded for 3-5 years, 6-8 years and 9-11 years have coded professionally for 0-2 years,3-5 years and 6-8 years professionally. THis most probably indicates that respondents start coding while in college and start coding professionally immediately after graduation.

Now, Let us take a look at the Languages, Frameworks and IDEs used by Developers.

survey %>% 
 filter(!is.na(LanguageWorkedWith)) %>%
  select(LanguageWorkedWith) %>%
  mutate(LanguageWorkedWith = str_split(LanguageWorkedWith, pattern = ";")) %>%
  unnest(LanguageWorkedWith) %>%
  group_by(LanguageWorkedWith) %>%
  count() %>%
  arrange(desc(n)) ->t
t$n <- round((t$n/size)*100,2)
highchart() %>%
hc_add_series(t,type="bar",hcaes(x="LanguageWorkedWith",y="n"),dataLabels = list(enabled = TRUE)) %>% 
  hc_legend(enabled=FALSE) %>%
  hc_colors("red") %>% 
  hc_title(text = 'Langauages Developers Have Worked With') %>%
  hc_xAxis(title=list(text="Language Worked With"),categories=t$LanguageWorkedWith) %>% 
  hc_yAxis(title=list(text="Percentage"),labels = list(format = "{value}%"))
survey %>% 
 filter(!is.na(LanguageWorkedWith)) %>%
  select(LanguageWorkedWith) %>%
  mutate(LanguageWorkedWith = str_split(LanguageWorkedWith, pattern = ";")) %>%
  unnest(LanguageWorkedWith) %>%
  group_by(LanguageWorkedWith) %>%
  count() %>%
  arrange(desc(n)) %>%
  hchart("treemap",hcaes(x=LanguageWorkedWith,value=n,color=n)) %>%
  hc_colorAxis(stops=color_stops(colors=viridis(10))) %>%
  hc_title(text="Languages Developers Have Worked With")

Top Languages Developers have worked with: JavaScript : 55.32% HTML : 54.25% CSS : 51.57% SQL : 45.19% Java : 35.93% Bash/Shell : 31.53% Python : 30.71 %

survey %>% 
 filter(!is.na(LanguageDesireNextYear)) %>%
  select(LanguageDesireNextYear) %>%
  mutate(LanguageDesireNextYear = str_split(LanguageDesireNextYear, pattern = ";")) %>%
  unnest(LanguageDesireNextYear) %>%
  group_by(LanguageDesireNextYear) %>%
  count() %>%
  arrange(desc(n)) ->t
t$n <- round((t$n/size)*100,2)
highchart() %>%
hc_add_series(t,type="bar",hcaes(x="LanguageDesireNextYear",y="n"),dataLabels = list(enabled = TRUE)) %>% 
  hc_legend(enabled=FALSE) %>%
  hc_colors("blue") %>% 
  hc_title(text = 'Langauages Developers Want to Work With') %>%
  hc_xAxis(title=list(text="Language"),categories=t$LanguageDesireNextYear) %>% 
  hc_yAxis(title=list(text="Percentage"),labels = list(format = "{value}%"))
survey %>% 
 filter(!is.na(LanguageDesireNextYear)) %>%
  select(LanguageDesireNextYear) %>%
  mutate(LanguageDesireNextYear = str_split(LanguageDesireNextYear, pattern = ";")) %>%
  unnest(LanguageDesireNextYear) %>%
  group_by(LanguageDesireNextYear) %>%
  count() %>%
  arrange(desc(n)) %>%
  hchart("treemap",hcaes(x=LanguageDesireNextYear,value=n,color=n)) %>%
  hc_colorAxis(stops=color_stops(colors=viridis(10))) %>%
  hc_title(text="Languages Developers Want to Work With")

Most of developers want to continue working with JavaScript, HTML and CSS, SQL and Bash/Shell. 33.17% of Developers would like to work with Python. Languages that developers currently don’t work with a lot but would like to work with are C++,C#,Kotlin,Swift.

The tree maps give a better visualization of Languages Worked With by developers and Languages they desire to work with.

Now, let us take a look at what languages people who have just begun coding learn.

survey %>% 
  filter(!is.na(LanguageWorkedWith)) %>%
  filter(!is.na(YearsCoding), YearsCoding %in% c("0-2 years")) %>%
  select(LanguageWorkedWith) %>%
  mutate(LanguageWorkedWith = str_split(LanguageWorkedWith, pattern = ";")) %>%
  unnest(LanguageWorkedWith) %>%
  group_by(LanguageWorkedWith) %>%
  count() %>%
  arrange(desc(n)) ->t
highchart() %>%
hc_add_series(t,type="bar",hcaes(x="LanguageWorkedWith",y="n"),dataLabels = list(enabled = TRUE)) %>% 
  hc_legend(enabled=FALSE) %>%
  hc_colors("blue") %>% 
  hc_title(text = 'Langauages Developers who have 0-2 years coding experience have worked with') %>%
  hc_xAxis(title=list(text="Language"),categories=t$LanguageWorkedWith) %>% 
  hc_yAxis(title=list(text="No. of respondents"))

This shows that a lot of people who have just begun coding start with HTML/CSS , JavaScript, SQL and Java.

Let us now take a look at IDE Preferences of Developers.

survey %>% 
 filter(!is.na(IDE)) %>%
  select(IDE) %>%
  mutate(IDE = str_split(IDE, pattern = ";")) %>%
  unnest(IDE) %>%
  group_by(IDE) %>%
  count() %>%
  arrange(desc(n)) ->t
t$n <- round((t$n/size)*100,2)
highchart() %>%
hc_add_series(t,type="bar",hcaes(x="IDE",y="n"),dataLabels = list(enabled = TRUE)) %>% 
  hc_legend(enabled=FALSE) %>%
  hc_colors("orange") %>% 
  hc_title(text = 'IDE Preferences of Developers') %>%
  hc_xAxis(title=list(text="IDE"),categories=t$IDE) %>% 
  hc_yAxis(title=list(text="Percentage"),labels = list(format = "{value}%"))
survey %>% 
 filter(!is.na(IDE)) %>%
  select(IDE) %>%
  mutate(IDE = str_split(IDE, pattern = ";")) %>%
  unnest(IDE) %>%
  group_by(IDE) %>%
  count() %>%
  arrange(desc(n)) %>%
  hchart("treemap",hcaes(x=IDE,value=n,color=n)) %>%
  hc_colorAxis(stops=color_stops(colors=plasma(10))) %>%
  hc_title(text="IDE Preferences of Developers")

Majority of Developers prefer Visual Studio Code, Visual Studio and Notepad++ while Sublime Text, Vim and IntelliJ remain popular options.

survey %>% 
 filter(!is.na(FrameworkWorkedWith)) %>%
  select(FrameworkWorkedWith) %>%
  mutate(FrameworkWorkedWith = str_split(FrameworkWorkedWith, pattern = ";")) %>%
  unnest(FrameworkWorkedWith) %>%
  group_by(FrameworkWorkedWith) %>%
  count() %>%
  arrange(desc(n)) ->t
t$n <- round((t$n/size)*100,2)
highchart() %>%
hc_add_series(t,type="bar",hcaes(x="FrameworkWorkedWith",y="n"),dataLabels = list(enabled = TRUE)) %>% 
  hc_legend(enabled=FALSE) %>%
  hc_colors("green") %>% 
  hc_title(text = 'Framework Developers Have Worked With') %>%
  hc_xAxis(title=list(text="Framework"),categories=t$FrameworkWorkedWith) %>% 
  hc_yAxis(title=list(text="Percentage"),labels = list(format = "{value}%"))
survey %>% 
 filter(!is.na(FrameworkWorkedWith)) %>%
  select(FrameworkWorkedWith) %>%
  mutate(FrameworkWorkedWith = str_split(FrameworkWorkedWith, pattern = ";")) %>%
  unnest(FrameworkWorkedWith) %>%
  group_by(FrameworkWorkedWith) %>%
  count() %>%
  arrange(desc(n)) %>%
  hchart("treemap",hcaes(x=FrameworkWorkedWith,value=n,color=n)) %>%
  hc_colorAxis(stops=color_stops(colors=inferno(10))) %>%
  hc_title(text="Frameworks Developers Have Worked With")

Considering that most people have worked with JavaScript,HTML and CSS, Node.js, Angular and React are the most popular Frameworks developers have worked with as they are all related to web development.

survey %>% 
 filter(!is.na(FrameworkDesireNextYear)) %>%
  select(FrameworkDesireNextYear) %>%
  mutate(FrameworkDesireNextYear = str_split(FrameworkDesireNextYear, pattern = ";")) %>%
  unnest(FrameworkDesireNextYear) %>%
  group_by(FrameworkDesireNextYear) %>%
  count() %>%
  arrange(desc(n)) ->t
t$n <- round((t$n/size)*100,2)
highchart() %>%
hc_add_series(t,type="bar",hcaes(x="FrameworkDesireNextYear",y="n"),dataLabels = list(enabled = TRUE)) %>% 
  hc_legend(enabled=FALSE) %>%
  hc_colors("green") %>% 
  hc_title(text = 'Framework Developers Want to Work With') %>%
  hc_xAxis(title=list(text="Framework"),categories=t$FrameworkDesireNextYear) %>% 
  hc_yAxis(title=list(text="Percentage"),labels = list(format = "{value}%"))
survey %>% 
 filter(!is.na(FrameworkDesireNextYear)) %>%
  select(FrameworkDesireNextYear) %>%
  mutate(FrameworkDesireNextYear = str_split(FrameworkDesireNextYear, pattern = ";")) %>%
  unnest(FrameworkDesireNextYear) %>%
  group_by(FrameworkDesireNextYear) %>%
  count() %>%
  arrange(desc(n)) %>%
  hchart("treemap",hcaes(x=FrameworkDesireNextYear,value=n,color=n)) %>%
  hc_colorAxis(stops=color_stops(colors=inferno(10))) %>%
  hc_title(text="Frameworks Developers want to Work With")

Node.js still remains at the top, but more developers want to explore React and Angular. TensorFlow is the Framework that a lot of people haven’t worked with yet, but would like to work with a lot. I believe this is due to increasing ML research and opportunities.

survey %>% 
 filter(!is.na(OperatingSystem)) %>%
  select(OperatingSystem) %>%
  mutate(OperatingSystem = str_split(OperatingSystem, pattern = ";")) %>%
  unnest(OperatingSystem) %>%
  group_by(OperatingSystem) %>%
  count() %>%
  plot_ly(type="pie",
          labels=~OperatingSystem,
          values=~n,
          textposition="inside",
          textinfo='label+percent+value',
          showlegend=FALSE,
          marker=list(colors = viridis(4))
  )%>%
          layout(title="Operating System Prefernce of Developers")

Windows still remains the popular Operating System Developers work with.

Part III: Salary Analysis

survey %>% 
  filter(!is.na(Country)) %>%
  filter(!is.na(ConvertedSalary)) %>%
  group_by(Country) %>%
  summarise(Median_salary=median(ConvertedSalary,na.rm = TRUE)) ->t
code <- countrycode(t$Country, 'country.name', 'iso3c')
t$iso3 <- code
highchart() %>%
    hc_add_series_map(worldgeojson, t, value = "Median_salary", joinBy = "iso3") %>%
    hc_colorAxis(stops=color_stops(colors=wes_palette("Cavalcanti1", 10, type = "continuous"))) %>%
    hc_title(text="Median Salary of Countries") %>%
    hc_add_theme(hc_theme_google())
NA
NA
survey %>%
  filter(Employment %in% 'Employed full-time') %>%
  ggplot() +
  geom_histogram(aes(ConvertedSalary),fill = "chocolate2")  +
  labs(x = "Annual Salary in USD", y = "Frequency",
       title = " Distribution of Annual Salary in USD") + theme_test() -> sal
sal

Note : Only the Salary of full time employees have been taken for the above distribution.

survey %>%
  filter(Employment %in% 'Employed full-time') %>%
  ggplot() +
  geom_histogram(aes(ConvertedSalary),fill = "chocolate4")  +
  scale_x_log10() +
  labs(x = "Log Annual Salary in USD", y = "Frequency",
       title = " Distribution of Annual Salary in USD on Log Scale") + theme_test() -> sal
sal

As we have seen in the beginning of the project, the most respondents have come from the following countries (Top 10) : United States, India, Germany, United Kingdom, Canada, Russia, France, Brazil, Poland, Australia (in order).

Let us see the distribution of people from these countries alone.

survey %>% filter(Employment %in% 'Employed full-time') %>% 
  group_by(Country) %>% 
  count() %>% 
  arrange(desc(n)) %>%
  head(10) %>%
  select(Country) %>% mutate(Country = factor(Country)) -> countries
options(scipen=999)
survey %>% filter(Employment %in% 'Employed full-time') %>% 
  group_by(Country) %>% 
  mutate(n = n()) %>% 
  filter(n > 1355) %>% 
  ungroup(Country) %>% 
  ggplot() +
  geom_violin(aes(Country,ConvertedSalary), fill= "deepskyblue4", color = "black") + theme_minimal()+
  scale_x_discrete(limits = countries$Country) + 
  coord_flip() +
  scale_y_log10() +
  labs(x = "Country", y = "Annual Salary in USD",
       title = "Distribution of Annual Salary(USD) of Top 10 Countries of respondents") -> p
ggplotly(p)
options(scipen=999)
survey %>% filter(Employment %in% 'Employed full-time') %>% 
  filter(Gender %in% c('Male','Female')) %>% 
  group_by(Country) %>% 
  mutate(n = n()) %>% 
  ungroup(Country) %>% 
  ggplot() +
  geom_boxplot(aes(Country,ConvertedSalary, fill = Gender))  + theme_minimal() +
  scale_fill_brewer(palette="Dark2") +
  scale_x_discrete(limits = countries$Country) +
  coord_flip() +
  scale_y_log10() + 
  labs(x = "Country", y = "Log of Annual Salary in USD",
       title = "Annual Salary in USD - Male vs Female of Top 10 countires by respondent") 

survey%>%
  select(DevType,ConvertedSalary,Age)%>%
  filter(!is.na(DevType),!is.na(ConvertedSalary),!is.na(Age)) %>%
  mutate(DevType=str_split(DevType,";"))%>%
  unnest(DevType)%>%group_by(Age,DevType)%>%
  summarise(avg_salary=round(median(ConvertedSalary),0))%>%
  ungroup()%>%
  hchart("spline",hcaes(x=Age,y=avg_salary,group=DevType)) %>%
 hc_title(text="Median Salary by developer type and age") %>%
  hc_xAxis(title=list(text="Age")) %>%
  hc_yAxis(title=list(text="Median Salary in USD"))
`summarise()` has grouped output by 'Age'. You can override using the `.groups` argument.
survey%>%
  select(DevType,ConvertedSalary)%>%
  filter(!is.na(DevType),!is.na(ConvertedSalary))%>%
  mutate(DevType=str_split(DevType,";"))%>%
  unnest(DevType)%>%
  group_by(DevType)%>%
  summarise(avg_salary=round(median(ConvertedSalary),0))%>%
  arrange(desc(avg_salary))%>%
  ungroup()%>% arrange(desc(avg_salary)) %>%
  hchart("lollipop",hcaes(x=DevType,y=avg_salary,group=DevType,size=avg_salary)) %>%
  hc_legend(enabled=FALSE) %>%
  hc_title(text="Median Salary by developer type") %>%
  hc_xAxis(title=list(text="Developer Type")) %>%
  hc_yAxis(title=list(text="Median Salary in USD"))
survey%>%
  select(DevType,ConvertedSalary,YearsCodingProf)%>%
  filter(!is.na(DevType),!is.na(ConvertedSalary),!is.na(YearsCodingProf))%>%
  mutate(YearsCoding=parse_number(as.character(YearsCodingProf)))%>%
  mutate(DevType=str_split(DevType,";"))%>%
  unnest(DevType)%>%
  group_by(DevType)%>%
  summarise(avg_salary=round(median(ConvertedSalary),0),n=n(),avg_years=mean(YearsCoding))%>%
  arrange(desc(n))%>%
  ungroup() -> t
hchart(t ,"bubble",hcaes(x=avg_years,y=avg_salary,group=DevType,size=n)) %>%
  hc_title(text="Professional Coding Experience vs Average Salary by Developer Type") %>%
  hc_xAxis(title=list(text="Average Professional Coding Experience in Years")) %>%
  hc_yAxis(title=list(text="Median Salary in USD")) %>%
  hc_legend(align = "right", layout = "vertical", verticalAlign = "top") %>%
  hc_add_theme(hc_theme_google())
survey%>%
  select(LanguageWorkedWith,ConvertedSalary)%>%
  filter(!is.na(LanguageWorkedWith),!is.na(ConvertedSalary))%>%
  mutate(LanguageWorkedWith=str_split(LanguageWorkedWith,";"))%>%
  unnest(LanguageWorkedWith)%>%
  group_by(LanguageWorkedWith)%>%
  summarise(avg_salary=round(median(ConvertedSalary),0))%>%
  arrange(desc(avg_salary))%>%
  ungroup()%>% arrange(desc(avg_salary)) %>%
  hchart("lollipop",hcaes(x=LanguageWorkedWith,y=avg_salary,group=LanguageWorkedWith,size=avg_salary)) %>%
  hc_legend(enabled=FALSE) %>%
  hc_title(text="Median Salary by Language Worked With") %>%
  hc_xAxis(title=list(text="Language Worked With")) %>%
  hc_yAxis(title=list(text="Median Salary in USD"))
survey%>%
  select(LanguageWorkedWith,ConvertedSalary,YearsCodingProf)%>%
  filter(!is.na(LanguageWorkedWith),!is.na(ConvertedSalary),!is.na(YearsCodingProf))%>%
  mutate(YearsCoding=parse_number(as.character(YearsCodingProf)))%>%
  mutate(LanguageWorkedWith=str_split(LanguageWorkedWith,";"))%>%
  unnest(LanguageWorkedWith)%>%
  group_by(LanguageWorkedWith)%>%
  summarise(avg_salary=round(median(ConvertedSalary),0),n=n(),avg_years=mean(YearsCoding))%>%
  arrange(desc(n))%>%
  ungroup() -> t
hchart(t ,"bubble",hcaes(x=avg_years,y=avg_salary,group=LanguageWorkedWith,size=n)) %>%
  hc_title(text="Professional Coding Experience vs Average Salary by Language Worked With") %>%
  hc_xAxis(title=list(text="Average Professional Coding Experience in Years")) %>%
  hc_yAxis(title=list(text="Median Salary in USD")) %>%
  hc_legend(align = "right", layout = "vertical", verticalAlign = "top") %>%
  hc_add_theme(hc_theme_google())

Part IV: Network Analysis

In a Network plot for X, Each node denotes the different X values and the size of node denotes the number of respondents for X. Each connecting edge between any two nodes denotes that the respondents chose both X values. And, the width of the edge denotes the number of users that chose both X values. Let us look at the network plots for Developer Types, Languages developers want to work with and IDEs they use.

survey %>% select(Respondent,DevType) -> t1
t1 %>% 
  mutate(DevType = strsplit(as.character(DevType), ";"))%>% 
  unnest(DevType) -> t2
         
t2 %>%
  group_by(Respondent)%>%
  filter(n()>=2)%>%
  do(data.frame(t(combn((.)[["DevType"]], 2)), stringsAsFactors=FALSE))%>% 
  ungroup()%>%
  rename(source = X1, target = X2)%>%
  select(-Respondent) -> t2_edges
t2_edges %>% 
  group_by(source,target)%>% 
  summarise(weight=n()) ->t2_edges
names(t2_edges) <- c("from","to","weight")
t2_edges$weight <- t2_edges$weight/1500

t2_edges$width <- 1+t2_edges$weight
t2_edges$smooth <- FALSE 
t2_edges$shadow <- FALSE

t2_nodes <- t2 %>% filter(!is.na(DevType)) %>% group_by(DevType) %>% summarise(n = n()/750) %>% arrange(desc(n))
names(t2_nodes) <- c("id","size")

n <- nrow(t2_nodes)
palette <- distinctColorPalette(n)

t2_nodes$shape <- "dot"  
t2_nodes$shadow <- TRUE
t2_nodes$title <- t2_nodes$id
t2_nodes$label <- t2_nodes$id
t2_nodes$size <- t2_nodes$size
t2_nodes$borderWidth <- 2

t2_nodes$color.background <- palette[as.numeric(as.factor(t2_nodes$id))]
t2_nodes$color.border <- "black"
t2_nodes$color.highlight.background <- "gold"
t2_nodes$color.highlight.border <- "gold"

visNetwork(t2_nodes, t2_edges,height = "1000px", width="100%") %>% visIgraphLayout(layout = "layout_with_lgl") %>% 
  visEdges(shadow = TRUE,
           color = list(color = "gray", highlight = "darkorange")) %>% visLegend()

From the network plot above, it can be seen that, it can be seen that the relationships with the highest correlation are Back-end developer — Full-stack developer Front-end developer — Full-stack developer Back-end developer — Front-end developer Back-end developer — Desktop or enterprise application developer

survey %>% select(Respondent,LanguageDesireNextYear) -> t1
t1 %>% 
  mutate(LanguageDesireNextYear = strsplit(as.character(LanguageDesireNextYear), ";"))%>% 
  unnest(LanguageDesireNextYear) -> t2
         
t2 %>%
  group_by(Respondent)%>%
  filter(n()>=2)%>%
  do(data.frame(t(combn((.)[["LanguageDesireNextYear"]], 2)), stringsAsFactors=FALSE))%>% 
  ungroup()%>%
  rename(source = X1, target = X2)%>%
  select(-Respondent) -> t2_edges
t2_edges %>% 
  group_by(source,target)%>% 
  summarise(weight=n()) ->t2_edges
names(t2_edges) <- c("from","to","weight")
t2_edges$weight <- t2_edges$weight/1500

t2_edges$width <- 1+t2_edges$weight
t2_edges$smooth <- FALSE 
t2_edges$shadow <- FALSE

t2_nodes <- t2 %>% filter(!is.na(LanguageDesireNextYear)) %>% group_by(LanguageDesireNextYear) %>% summarise(n = n()/750) %>% arrange(desc(n))
names(t2_nodes) <- c("id","size")

n <- nrow(t2_nodes)
palette <- distinctColorPalette(n)

t2_nodes$shape <- "circle"  
t2_nodes$shadow <- TRUE
t2_nodes$title <- t2_nodes$id
t2_nodes$label <- t2_nodes$id
t2_nodes$size <- t2_nodes$size
t2_nodes$borderWidth <- 2

t2_nodes$color.background <- palette[as.numeric(as.factor(t2_nodes$id))]
t2_nodes$color.border <- "black"
t2_nodes$color.highlight.background <- "purple"
t2_nodes$color.highlight.border <- "purple"

visNetwork(t2_nodes, t2_edges,height = "1200px", width="100%") %>% visIgraphLayout(layout = "layout_with_lgl") %>% 
  visEdges(shadow = TRUE,
           color = list(color = "gray", highlight = "magenta")) %>% visLegend()

The relationships with highest correlation are: HTML — CSS HTML — JavaScript CSS — JavaScript HTML — SQL SQL — JavaScript CSS — SQL Python — SQL Python — JavaScript

survey %>% select(Respondent,IDE) -> t1
t1 %>% 
  mutate(IDE = strsplit(as.character(IDE), ";"))%>% 
  unnest(IDE) -> t2
         
t2 %>%
  group_by(Respondent)%>%
  filter(n()>=2)%>%
  do(data.frame(t(combn((.)[["IDE"]], 2)), stringsAsFactors=FALSE))%>% 
  ungroup()%>%
  rename(source = X1, target = X2)%>%
  select(-Respondent) ->t2_edges
t2_edges %>% 
  group_by(source,target)%>% 
  summarise(weight=n()) ->t2_edges
names(t2_edges) <- c("from","to","weight")
t2_edges$weight <- t2_edges$weight/1500

t2_edges$width <- 1+t2_edges$weight
t2_edges$smooth <- FALSE 
t2_edges$shadow <- FALSE

t2_nodes <- t2 %>% filter(!is.na(IDE)) %>% group_by(IDE) %>% summarise(n = n()/750) %>% arrange(desc(n))
names(t2_nodes) <- c("id","size")

n <- nrow(t2_nodes)
palette <- distinctColorPalette(n)

t2_nodes$shape <- "triangle"  
t2_nodes$shadow <- TRUE
t2_nodes$title <- t2_nodes$id
t2_nodes$label <- t2_nodes$id
t2_nodes$size <- t2_nodes$size
t2_nodes$borderWidth <- 2

t2_nodes$color.background <- palette[as.numeric(as.factor(t2_nodes$id))]
t2_nodes$color.border <- "black"
t2_nodes$color.highlight.background <- "chocolate"
t2_nodes$color.highlight.border <- "chocolate"

visNetwork(t2_nodes, t2_edges,height = "1000px", width="100%") %>% visIgraphLayout(layout = "layout_with_lgl") %>% 
  visEdges(shadow = TRUE,
           color = list(color = "gray", highlight = "brown")) %>% visLegend()

```

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgd29yZF9kb2N1bWVudDogZGVmYXVsdA0KYWx3YXlzX2FsbG93X2h0bWw6IHllcw0KLS0tDQoNCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHZpcmlkaXMpDQpsaWJyYXJ5KHdlc2FuZGVyc29uKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KbGlicmFyeSh2aXNOZXR3b3JrKQ0KbGlicmFyeShyYW5kb21jb2xvUikNCmBgYA0KDQpgYGB7cn0NCnN1cnZleSA8LSByZWFkLmNzdigiRjpcXERhdGFWaXpcXFByb2plY3RcXHN1cnZleV9yZXN1bHRzX3B1YmxpYy5jc3YiKQ0Kc2NoZW1hIDwtIHJlYWQuY3N2KCJGOlxcRGF0YVZpelxcUHJvamVjdFxcc3VydmV5X3Jlc3VsdHNfc2NoZW1hLmNzdiIpDQpgYGANCg0KVGhlIGRhdGFzZXRzIGhhdmUgYmVlbiBpbXBvcnRlZC4NCnN1cnZleSByZXByZXNlbnRzIHRoZSByZXN1bHRzIG9mIHRoZSBzdXJ2ZXkNCnNjaGVtYSByZXByZXNlbnRzIHRoZSBxdWVzdGlvbnMgYXNrZWQgZHVyaW5nIHRoZSBzdXJ2ZXkuDQoNCkJlZm9yZSBleHBsb3JpbmcgdGhlIHJlc3VsdHMgb2YgdGhlIHN1cnZleSwgbGV0IHVzIHRha2UgYSBsb29rIGF0IHRoZSBxdWVzdGlvbnMgYXNrZWQgZHVyaW5nIHRoZSBzdXJ2ZXkuDQoNCmBgYHtyfQ0Ka2FibGUoc2NoZW1hKQ0KYGBgDQoNCmBgYHtyfQ0KZ2xpbXBzZShzdXJ2ZXkpDQpgYGANCg0KRnJvbSB0aGUgZ2xpbXBzZSwgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBzb21lIG51bGwgdmFsdWVzIGluIHNvbWUgcXVlc3Rpb25zLiBUaGlzIGlzIGR1ZSB0byB0aGUgZmFjdCB0aGF0IG1vc3Qgb2YgdGhlIHF1ZXN0aW9ucyBhcmUgb3B0aW9uYWwgaW4gdGhlIHN1cnZleS4gRm9yIHRoZSBzYWtlIG9mIGV4cGxvcmF0aW9uIG9mIHRoaXMgZGF0YXNldCwgd2Ugd2lsbCBub3QgYmUgY29uc2lkZXJpbmcgbnVsbCB2YWx1ZXMgYnV0IGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIGV4cGxvcmUgd2h5IGEgZmV3IHF1ZXN0aW9ucyBoYXZlIGJlZW4gYW5zd2VyZWQgbnVsbCBieSB0aGUgcmVzcG9uZGVudHMuDQoNCmBgYHtyfQ0KDQpgYGANCg0KDQpQYXJ0IEkgOiBHZW5lcmFsIGV4cGxvcmF0aW9uIG9mIHN1cnZleSByZXN1bHRzDQoNCkxldCdzIHNlZSB3aGljaCBjb3VudHJpZXMgaGF2ZSB0aGUgbWF4aW11bSByZXNwb25kZW50cyBvZiB0aGUgc3VydmV5Lg0KDQpgYGB7cn0NCnN1cnZleSAlPiUgDQogIGdyb3VwX2J5KENvdW50cnkpICU+JQ0KICBjb3VudCgpICU+JQ0KICBhcnJhbmdlKGRlc2MobikpICU+JQ0KICBoZWFkKDIwKSAlPiUNCiAgaGNoYXJ0KCd0cmVlbWFwJyxoY2Flcyh4PUNvdW50cnksIHZhbHVlPW4sIGNvbG9yPW4pKSAlPiUNCiAgaGNfY29sb3JBeGlzKHN0b3BzPWNvbG9yX3N0b3BzKGNvbG9ycz1wbGFzbWEoMTApKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IlRvcCAyMCBDb3VudHJpZXMgb2YgcmVzcG9uZGVudHMgb2Ygc3VydmV5IikNCmBgYA0KQXMgd2UgY2FuIHNlZSBmcm9tIHRoZSBhYm92ZSB0cmVlIG1hcCwgdGhlIGNvdW50cnkgd2l0aCB0aGUgbWF4aW11bSBudW1iZXIgb2YgcmVzcG9uZGVudHMgY29tZSBmcm9tIFVuaXRlZCBTdGF0ZXMgd2l0aCBJbmRpYSBhdCBzZWNvbmQgcG9zaXRpb24gd2hpbGUgR2VybWFueSwgVW5pdGVkIEtpbmdkb20gYW5kIENhbmFkYSBtYWtlIHVwIHRoZSB0b3AgNS4gDQpMZXQgdXMgYWxzbyB0YWtlIGEgbG9vayBhdCB0aGUgcGVyY2VudGFnZSBkaXN0cmlidXRpb24gb2YgcmVzcG9uZGVudHMNCg0KYGBge3J9DQpzaXplPW5yb3coc3VydmV5KQ0Kc3VydmV5ICU+JSANCiAgZ3JvdXBfYnkoQ291bnRyeSkgJT4lDQogIGNvdW50KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogIGhlYWQoMjApICU+JQ0KICBoY2hhcnQoJ2JhcicsaGNhZXMoeD1Db3VudHJ5LCB5PXJvdW5kKChuL3NpemUpKjEwMCwyKSkpICU+JQ0KICBoY19jb2xvckF4aXMoc3RvcHM9Y29sb3Jfc3RvcHMoY29sb3JzPXBsYXNtYSgxMCkpKSAlPiUNCiAgaGNfdGl0bGUodGV4dD0iVG9wIDIwIENvdW50cmllcyBvZiByZXNwb25kZW50cyBvZiBzdXJ2ZXkiKSAlPiUNCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJQZXJjZW50YWdlIG9mIHJlc3BvbmRlbnRzIiksbGFiZWxzID0gbGlzdChmb3JtYXQgPSAie3ZhbHVlfSUiKSkgJT4lDQogIGhjX2FkZF90aGVtZShoY190aGVtZV90dWZ0ZSgpKQ0KYGBgDQoNCkZyb20gdGhlIGJhciBjaGFydCBhYm92ZSwgd2UgY2FuIHNlZSB0aGF0IDoNCjIwLjU0JSBvZiByZXNwb25kZW50cyBhcmUgZnJvbSB0aGUgVW5pdGVkIFN0YXRlcw0KMTMuODglIG9mIHJlc3BvbmRlbnRzIGFyZSBmcm9tIEluZGlhDQpHZXJtYW55KDYuNTMlKSxVbml0ZWQgS2luZ2RvbSg2LjI5JSkgYW5kIENhbmFkYSgzLjQzJSkgaGF2ZSB0aGUgbmV4dCAzIGhpZ2hlc3QgcmVzcG9uZGVudHMuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBncm91cF9ieShDb3VudHJ5KSAlPiUNCiAgY291bnQoKSAtPiBjb3VudHJ5DQogIGNvdW50cnkkQ291bnRyeSA8LSBhcy5jaGFyYWN0ZXIoY291bnRyeSRDb3VudHJ5KQ0KICBjb3VudHJ5W2NvdW50cnk9PSJVbml0ZWQgU3RhdGVzIl0gPC0gIlVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYSINCiAgY291bnRyeVtjb3VudHJ5PT0iUnVzc2lhbiBGZWRlcmF0aW9uIl0gPC0gIlJ1c3NpYSINCiAgaGlnaGNoYXJ0KCkgJT4lDQogICAgaGNfYWRkX3Nlcmllc19tYXAod29ybGRnZW9qc29uLGNvdW50cnksdmFsdWU9J24nLGpvaW5CeT1jKCduYW1lJywnQ291bnRyeScpKSAlPiUNCiAgICBoY19jb2xvckF4aXMoc3RvcHM9Y29sb3Jfc3RvcHMoY29sb3JzPXZpcmlkaXMoMTApKSkgJT4lDQogICAgaGNfdGl0bGUodGV4dD0iQ291bnRyaWVzIGJ5IG5vLiBvZiByZXNwb25kZW50cyIpICU+JQ0KICAgIGhjX2FkZF90aGVtZShoY190aGVtZV90dWZ0ZSgpKQ0KICAgIA0KYGBgDQpUaGUgYWJvdmUgbWFwIGlzIGEgYmV0dGVyIHZpc3VhbGl6YXRpb24gb2YgYWxsIHRoZSByZXNwb25kZW50cyBieSBjb3VudHJ5Lg0KDQpOb3csIGxldCB1cyBsb29rIGF0IGhvdyBtYW55IHJlc3BvbmRlbnRzIHRha2UgdXAgY29kaW5nIGFzIGEgaG9iYnkuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBncm91cF9ieShIb2JieSkgJT4lDQogIGNvdW50KCkgJT4lDQogIHBsb3RfbHkodHlwZT0icGllIiwNCiAgICAgICAgICBsYWJlbHM9fkhvYmJ5LA0KICAgICAgICAgIHZhbHVlcz1+biwNCiAgICAgICAgICB0ZXh0cG9zaXRpb249Imluc2lkZSIsDQogICAgICAgICAgdGV4dGluZm89J2xhYmVsK3BlcmNlbnQrdmFsdWUnLA0KICAgICAgICAgIHNob3dsZWdlbmQ9RkFMU0UsDQogICAgICAgICAgbWFya2VyPWxpc3QoY29sb3JzID0gdmlyaWRpcygyKSkNCiAgKSU+JQ0KICAgICAgICAgIGxheW91dCh0aXRsZT0iSXMgY29kaW5nIGEgaG9iYnkgZm9yIHJlc3BvbmRlbnRzPyIpDQogIA0KYGBgDQpGcm9tIHRoZSBhYm92ZSBwaWVjaGFydCwgd2UgY2FuIHNlZSB0aGF0IG1vcmUgdGhhbiA4MCUgb2YgdGhlIHJlc3BvbmRlbnRzIHRha2UgdXAgY29kaW5nIGFzIGEgaG9iYnkuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBncm91cF9ieShPcGVuU291cmNlKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgcGxvdF9seSh0eXBlPSJwaWUiLA0KICAgICAgICAgIGxhYmVscz1+T3BlblNvdXJjZSwNCiAgICAgICAgICB2YWx1ZXM9fm4sDQogICAgICAgICAgdGV4dHBvc2l0aW9uPSJpbnNpZGUiLA0KICAgICAgICAgIHRleHRpbmZvPSdsYWJlbCtwZXJjZW50K3ZhbHVlJywNCiAgICAgICAgICBzaG93bGVnZW5kPUZBTFNFLA0KICAgICAgICAgIG1hcmtlcj1saXN0KGNvbG9ycyA9IHZpcmlkaXMoMikpDQogICklPiUNCiAgICAgICAgICBsYXlvdXQodGl0bGU9IkRvIHJlc3BvbmRlbnRzIGNvbnRyaWJ1dGUgdG8gT3BlblNvdXJjZSBQcm9qZXRzPyIpDQpgYGANCg0KRnJvbSB0aGUgYWJvdmUgcGllY2hhcnQsIHdlIGNhbiBzZWUgdGhhdCBhcm91bmQgNTYlIG9mIHJlc3BvbmRlbnRzIGNvbnRyaWJ1dGUgdG8gb3BlbiBzb3VyY2UgcHJvamVjdHMuDQoNCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBnZW5kZXIgb2YgcmVzcG9uZGVudHMuDQoNCmBgYHtyfQ0KICBTIDwtIHN1bShpcy5uYShzdXJ2ZXkkR2VuZGVyKSkNCiAgUw0KICByb3VuZCgoUy9zaXplKSoxMDAsMikNCmBgYA0KV2Ugc2VlIHRoYXQgYWxtb3N0IDM0Mzg2KDM0Ljc4JSkgcmVzcG9uZGVudHMgaGF2ZSBub3QgZGlzY2xvc2VkIHRoZWlyIGdlbmRlciBpbiB0aGUgc3VydmV5LiBJdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBrbm93IHRoZSByZWFzb24gYmVoaW5kIHRoaXMuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JSANCiAgZmlsdGVyKCFpcy5uYShHZW5kZXIpKSAlPiUNCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgcGxvdF9seSh0eXBlPSJwaWUiLA0KICAgICAgICAgIGxhYmVscz1+R2VuZGVyLA0KICAgICAgICAgIHZhbHVlcz1+biwNCiAgICAgICAgICB0ZXh0cG9zaXRpb249Imluc2lkZSIsDQogICAgICAgICAgdGV4dGluZm89J2xhYmVsK3BlcmNlbnQnLA0KICAgICAgICAgIHNob3dsZWdlbmQ9RkFMU0UsDQogICAgICAgICAgbWFya2VyPWxpc3QoY29sb3JzID0gdmlyaWRpcygxMCkpDQogICkgJT4lDQogIGxheW91dCh0aXRsZT0iR2VuZGVyIG9mIHJlc3BvbmRlbnRzIikNCmBgYA0KVGhlIHJlc3VsdHMgYXJlIHZlcnkgc2hvY2tpbmcuIFdlIGNhbiBzZWUgdGhhdCA5Mi4yJSByZXNwb25kZW50cyB3aG8gZ2F2ZSB0aGVpciBnZW5kZXIgYXJlIG1hbGUsIDYuMjQlIG9mIHRoZSByZXNwb25kZW50cyBhcmUgZmVtYWxlIHdoaWxlIHRoZSByZXN0IGFyZSB0cmFuc2dlbmRlciwgbm9uLWJpbmFyeSBvciBnZW5kZXIgbm9uLWNvbmZvcm1pbmcuIFRoZSByZXN1bHRzIG1heWJlIG1pc2xlYWRpbmcgZHVlIHRvIHRoZSBmYWN0IHRoYXQgMzQuNzglIG9mIHRoZSByZXNwb25kZW50cyBoYXZlIG5vdCBkaXNjbG9zZWQgdGhlaXIgZ2VuZGVyLiBUaGUgcmVhc29ucyBmb3IgdGhpcyBpcyBub3Qga25vd24sIGJ1dCB0aGUgYWJvdmUgY2hhcnQgc2hvd3MgdXMgdGhhdCB0aGVyZSBleGlzdHMgYSBodWdlIGdlbmRlciBnYXAgaW4gdGhlIFN0YWNrT3ZlcmZsb3cgQ29tbXVuaXR5Lg0KTm93LCBsZXQncyB0YWtlIGEgbG9vayBhdCB3aGV0aGVyIHRoZSByZXNwb25kZW50cyBhcmUgc3R1ZGVudHMgYW5kIHRoZWlyIGN1cnJlbnQgZW1wbG95bWVudCBzdGF0dXMuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBmaWx0ZXIoIWlzLm5hKFN0dWRlbnQpKSAlPiUNCiAgZ3JvdXBfYnkoU3R1ZGVudCklPiUNCiAgY291bnQoKSAlPiUNCiAgaGNoYXJ0KCJwaWUiLGhjYWVzKHg9U3R1ZGVudCx5PXJvdW5kKChuL3NpemUpKjEwMCwyKSkpICU+JQ0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZmZ4KCkpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJBcmUgdGhlIHJlc3BvbmRlbnRzIHN0dWRlbnRzPyIsYWxpZ249ImNlbnRlciIsc3R5bGUgPSBsaXN0KGZvbnRXZWlnaHQ9ImJvbGQiLCBmb250U2l6ZT0iMzBweCIpKQ0KYGBgDQpGcm9tIHRoZSBhYm92ZSBwaWUgY2hhcnQsIHdlIGNhbiBzZWUgdGhhdCBtb3JlIHRoYXQgNzEuMjElIG9mIHRoZSByZXNwb25kZW50cyBhcmUgbm90IHN0dWRlbnRzLCAxOC42MSUgYXJlIGZ1bGwgdGltZSBzdHVkZW50cyB3aGlsZSA2LjE4IGFyZSBwYXJ0LXRpbWUgc3R1ZGVudHMuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBmaWx0ZXIoIWlzLm5hKEVtcGxveW1lbnQpKSAlPiUNCiAgZ3JvdXBfYnkoRW1wbG95bWVudCklPiUNCiAgY291bnQoKSAlPiUNCiAgaGNoYXJ0KCJwaWUiLGhjYWVzKHg9RW1wbG95bWVudCx5PXJvdW5kKChuL3NpemUpKjEwMCwyKSkpICU+JQ0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZmZ4KCkpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJFbXBsb3ltZW50IHN0YXR1cyBvZiB0aGUgcmVzcG9uZGVudHMiLGFsaWduPSJjZW50ZXIiLHN0eWxlID0gbGlzdChmb250V2VpZ2h0PSJib2xkIiwgZm9udFNpemU9IjMwcHgiKSkNCmBgYA0KRnJvbSwgdGhlIGFib3ZlIHBpZSBjaGFydCwgd2UgY2FuIHNlZSB0aGF0IDcxLjMxJSBhcmUgZW1wbG95ZWQgZnVsbCB0aW1lLCA1LjQ0JSBhcmUgZW1wbG95ZWQgcGFydCB0aW1lLCA5LjM5JSBhcmUgc2VsZi1lbXBsb3llZCBvciBmcmVlbGFuY2VycyB3aGlsZSAyMC4wNSUgYXJlIG5vdCBlbXBsb3llZC4gSXQgaXMgcmVmcmVzaGluZyB0byBzZWUgdGhhdCBmdWxsIHRpbWUgZW1wbG95ZWVzIHRha2UgdGltZSB0byBjb250cmlidXRlIHRvIHRoZSBTdGFja092ZXJmbG93IENvbW11bml0eS4NCg0KTm93LCBsZXQgdXMgdGFrZSBhIGxvb2sgYXQgdGhlIGVkdWNhdGlvbiBvZiB0aGUgcmVzcG9uZGVudHMuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBmaWx0ZXIoIWlzLm5hKEZvcm1hbEVkdWNhdGlvbikpICU+JQ0KICBncm91cF9ieShGb3JtYWxFZHVjYXRpb24pICU+JQ0KICBjb3VudCgpICU+JQ0KICBoY2hhcnQoImJhciIsaGNhZXMoeD1Gb3JtYWxFZHVjYXRpb24seT1uKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IkhpZ2hlc3QgTGV2ZWwgb2YgRm9ybWFsIEVkdWNhdGlvbiBvZiByZXNwb25kZW50cyIsc3R5bGU9bGlzdChmb250V2VpZ2h0PSJib2xkIikpICU+JQ0KICBoY195QXhpcyh0aXRsZT1saXN0KHRleHQ9Ik5vIG9mIHJlc3BvbmRlbnRzIixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9IkhpZ2hlc3QgTGV2ZWwgb2YgRnJvbWFsIEVkdWNhdGlvbiIsc3R5bGU9bGlzdChmb250V2VpZ2h0PSJib2xkIikpKSAlPiUNCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2Z0KCkpICU+JQ0KICBoY19jb2xvcnMoImJsYWNrIikNCmBgYA0KV2UgY2FuIHNlZSB0aGF0IG1ham9yaXR5IG9mIHJlc3BvbmRlbnRzIGhhdmUgcmVjZWl2ZWQgYSBiYWNoZWxvcidzIGRlZ3JlZSBvciBhIG1hc3RlcidzIGRlZ3JlZS4gT25seSBhIHZlcnkgZmV3IHN0dWRlbnRzIGhhdmUgbm90IGNvbXBsZXRlZCBhbnkgZm9ybWFsIGVkdWNhdGlvbi4NCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgd2hhdCB0aGUgcmVzcG9uZGVudHMgaGF2ZSBtYWpvcmVkIGluIGR1cmluZyB0aGVpciB1bmRlcmdyYWR1YXRpb24uDQoNCmBgYHtyfQ0KUyA8LSBzdW0oaXMubmEoc3VydmV5JFVuZGVyZ3JhZE1ham9yKSkNClMNCnJvdW5kKChTL3NpemUpKjEwMCwyKQ0KYGBgDQpBcyB3ZSBjYW4gc2VlIGFib3ZlLCBhcm91bmQgMjAlIG9mIHJlc3BvbmRlbnRzIGhhdmUgbm90IGRpc2Nsb3NlZCB0aGVpciB1bmRlcmdyYWQgbWFqb3IuIFRoaXMgY2FuIGJlIGV4cGxhaW5lZCBieSB0aGUgZmFjdCB0aGF0IGFsbW9zdCAyMCUgb2Ygc3R1ZGVudHMgaGF2ZSBlaXRoZXIgbm90IHJlY2VpdmVkIGFuIHVuZGVyZ3JhZCBkZWdyZWUgYXMgdGhleSBoYXZlIG9ubHkgY29tcGxldGVkIHRoZWlyIHNjaG9vbGluZywgaGF2ZW4ndCBoYWQgYW55IGZvcm1hbCBlZHVjYXRpb24gb3IgaGF2ZSBzdHVkaWVkIGluIGNvbGxlZ2Ugd2l0aG91dCBlYXJuaW5nIGEgZGVncmVlLiBUaGlzIGNhbiBiZSBzZWVuIGluIHRoZSBwcmV2aW91cyBiYXJwbG90Lg0KDQpgYGB7cn0NCnN1cnZleSAlPiUNCiAgZmlsdGVyKCFpcy5uYShVbmRlcmdyYWRNYWpvcikpICU+JQ0KICBncm91cF9ieShVbmRlcmdyYWRNYWpvcikgJT4lDQogIGNvdW50KCkgJT4lDQogIGhjaGFydCgiYmFyIixoY2Flcyh4PVVuZGVyZ3JhZE1ham9yLHk9cm91bmQoKG4vc2l6ZSkqMTAwLDIpKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IlVuZGVyZ3JhZHVhdGlvbiBNYWpvcnMgb2YgcmVzcG9uZGVudHMiLHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSAlPiUNCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJQZXJjZW50IG9mIHJlc3BvbmRlbnRzIixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSksbGFiZWxzID0gbGlzdChmb3JtYXQgPSAie3ZhbHVlfSUiKSkgJT4lDQogIGhjX3hBeGlzKHRpdGxlPWxpc3QodGV4dD0iTWFqb3IiLHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSkgJT4lDQogIGhjX2FkZF90aGVtZShoY190aGVtZV9mdCgpKSAlPiUNCiAgaGNfY29sb3JzKCJwdXJwbGUiKSANCmBgYA0KVGhlIHJlc3VsdHMgYXJlIG9idmlvdXMgYXMgYWJvdXQgNTAuOTIlIG9mIHJlc3BvbmRlbnRzIGhhdmUgYSBtYWpvciBpbiBDb21wdXRlciBTY2llbmNlIHN0cmVhbSwgNy4wMyUgYXJlIGZyb20gYW5vdGhlciBlbmdpbmVlcmluZyBkaXNjaXBsaW5lLCA2LjU4JSBhcmUgZnJvbSB0aGUgSVQgc3RyZWFtLiANCg0KTm93IHRoYXQgd2UndmUgZ2VuZXJhbGx5IGV4cGxvcmVkIGEgZmV3IHJlc3BvbnNlcyBmcm9tIHRoZSBzdXJ2ZXksIGxldCB1cyB0cnkgdG8gZmluZCBhIGZldyByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlc2UgcmVzcG9uc2VzDQpgYGB7cn0NCnN1cnZleSAlPiUNCiAgY291bnQoSG9iYnksT3BlblNvdXJjZSkgJT4lDQogIGhjaGFydCgiY29sdW1uIixoY2Flcyh4PUhvYmJ5LHk9bixncm91cD1PcGVuU291cmNlKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IkNvbnRyaWJ1dGlvbiB0byBPcGVuU291cmNlIFByb2plY3RzIGJ5IENvZGluZyBhcyBhIEhvYmJ5IixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkgJT4lDQogIGhjX3lBeGlzKHRpdGxlPWxpc3QodGV4dD0iTm8uIG9mIHJlc3BvbmRlbnRzIixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSkNCmBgYA0KSXQncyBwcmV0dHkgY2xlYXIgdGhhdCBwZW9wbGUgd2hvIGNvZGUgYXMgYSBob2JieSB0ZW5kIHRvIGNvbnRyaWJ1dGUgbW9yZSB0byBvcGVuc291cmNlIHByb2plY3RzLg0KDQpMZXQncyBmaXJzdCBsb29rIGF0IHdoZXRoZXIgcmVzcG9uZGVudHMgY29kZSBhcyBhIGhvYmJ5IGFuZCBjb250cmlidXRlIHRvIG9wZW4gc291cmNlIGFjY29yZGluZyB0byB0aGVpciBzdHVkZW50IGFuZCBlbXBsb3ltZW50IHN0YXR1cw0KDQpgYGB7cn0NCnN1cnZleSAlPiUgDQogIGZpbHRlcighaXMubmEoU3R1ZGVudCkpICU+JQ0KICBjb3VudChIb2JieSxTdHVkZW50KSAlPiUNCiAgaGNoYXJ0KCJiYXIiLGhjYWVzKHg9SG9iYnkseT1uLGdyb3VwPVN0dWRlbnQpKSAlPiUNCiAgaGNfdGl0bGUodGV4dD0iQ29kaW5nIGFzIGEgaG9iYnkgYnkgU3R1ZGVudCBTdGF0dXMiLHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSAlPiUNCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJOby4gb2YgcmVzcG9uZGVudHMiLHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSkgJT4lDQogIGhjX3hBeGlzKHRpdGxlPWxpc3Qoc3R5bGU9bGlzdChmb250V2VpZ2h0PSJib2xkIikpKSAlPiUNCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2Rhcmt1bmljYSgpKQ0KYGBgDQpJdCBpcyBnb29kIHRvIHNlZSB0aGF0IG1vcmUgbnVtYmVyIG9mIHN0dWRlbnRzIGFyZSBjb2RpbmcgYXMgYSBob2JieSByYXRoZXIgdGhhdCBzdHVkeWluZyBpdCBmb3IgdGhlIHNha2Ugb2YgdW5pdmVyc2l0eS4NCmBgYHtyfQ0Kc3VydmV5ICU+JSANCiAgZmlsdGVyKCFpcy5uYShTdHVkZW50KSkgJT4lDQogIGNvdW50KE9wZW5Tb3VyY2UsU3R1ZGVudCkgJT4lDQogIGhjaGFydCgiYmFyIixoY2Flcyh4PU9wZW5Tb3VyY2UseT1uLGdyb3VwPVN0dWRlbnQpKSAlPiUNCiAgaGNfdGl0bGUodGV4dD0iQ29udHJpYnV0aW9uIHRvIE9wZW5Tb3VyY2UgUHJvamVjdHMgYnkgU3VkZW50IFN0YXR1cyIsc3R5bGU9bGlzdChmb250V2VpZ2h0PSJib2xkIikpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9Ik5vLiBvZiByZXNwb25kZW50cyIsc3R5bGU9bGlzdChmb250V2VpZ2h0PSJib2xkIikpKSAlPiUNCiAgaGNfeUF4aXModGl0bGU9bGlzdChzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkpICU+JQ0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZGFya3VuaWNhKCkpDQpgYGANCkl0IGNhbiBiZSBzZWVuIHRoYXQgbW9zdCBwZW9wbGUgd2hvIGFyZSBub3Qgc3R1ZGVudHMgY29udHJpYnV0ZSB0byBvcGVuIHNvdXJjZSBwcm9qZWN0cywgd2hpbGUgZnVsbCB0aW1lIHN0dWRlbnRzIGNvbnRyaWJ1dGUgdG8gb3BlbiBzb3VyY2UgcHJvamVjdHMgdGhlIGxlYXN0LiBUaGlzIGlzIHdvcnJ5aW5nIHRvIHNlZSBhcyBjb250cmlidXRpbmcgdG8gb3BlbiBzb3VyY2UgcHJvamVjdHMgbWF5IGJlIGEgZ3JlYXQgd2F5IHRvIGxlYXJuIGZvciBzdHVkZW50cy4NCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKEVtcGxveW1lbnQpKSAlPiUNCiAgY291bnQoT3BlblNvdXJjZSxFbXBsb3ltZW50KSAlPiUNCiAgaGNoYXJ0KCJjb2x1bW4iLGhjYWVzKHg9RW1wbG95bWVudCx5PW4sZ3JvdXA9T3BlblNvdXJjZSkpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJDb250cmlidXRpb24gdG8gT3BlblNvdXJjZSBQcm9qZWN0cyBieSBFbXBsb3ltZW50IFN0YXR1cyIsc3R5bGU9bGlzdChmb250V2VpZ2h0PSJib2xkIikpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9Ik5vLiBvZiByZXNwb25kZW50cyIsc3R5bGU9bGlzdChmb250V2VpZ2h0PSJib2xkIikpKSAlPiUNCiAgaGNfeUF4aXModGl0bGU9bGlzdChzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkpICU+JQ0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZmxhdCgpKQ0KYGBgDQoNClRoZSByZXN1bHRzIGFyZSBwcmV0dHkgY2xlYXIgdGhhdCByZXNwb25kZW50cyB3aG8gYXJlIGVtcGxveWVkIGZ1bGwgdGltZSBkbyBub3QgY29udHJpYnV0ZSBtb3JlIHRvIE9wZW4gU291cmNlIFByb2plY3RzIHdoaWxlIEZyZWVsYW5jZXJzIGFuZCBJbmRlcGVuZGVudCBjb250cmFjdG9ycyB0ZW5kIHRvIGNvbnRyaWJ1dGUgbW9yZSB0byBPcGVuIFNvdXJjZSBQcm9qZWN0cy4gSG93ZXZlciwgdGhlIHJlc3VsdHMgYXJlIHB1enpsaW5nIHRoYXQgcmVzcG9uZGVudHMgd2hvIGFyZSBlbXBsb3llZCBwYXJ0IHRpbWUgb3Igbm90IGVtcGxveWVkIGRvIG5vdCBjb250cmlidXRlIG1vcmUgdG8gT3BlbiBTb3VyY2UgUHJvamVjdHMuDQoNCk5leHQsIExldCB1cyB0YWtlIGEgbG9vayBhdCB0aGUgY3VycmVudCBFbXBsb3ltZW50IFN0YXR1cyB2cyB3aGVyZSByZXNwb25kZW50cyBob3BlIHRvIGJlIGluIGZpdmUgeWVhcnMuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JSANCiAgZmlsdGVyKCFpcy5uYShFbXBsb3ltZW50KSkgJT4lDQogIGZpbHRlcighaXMubmEoSG9wZUZpdmVZZWFycykpICU+JQ0KICBjb3VudChFbXBsb3ltZW50LEhvcGVGaXZlWWVhcnMpICU+JQ0KICBoY2hhcnQoImJhciIsaGNhZXMoeD1Ib3BlRml2ZVllYXJzLHk9bixncm91cD1FbXBsb3ltZW50KSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IkN1cnJlbnQgRW1wbG95bWVudCB2cyBIb3BlIGluIEZpdmUgWWVhcnMiLHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSAlPiUNCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJOby4gb2YgcmVzcG9uZGVudHMiLHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSkgJT4lDQogIGhjX3hBeGlzKHRpdGxlPWxpc3QodGV4dD0iSG9wZSBpbiBGaXZlIFllYXJzIixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkpICU+JQ0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZ29vZ2xlKCkpDQpgYGANCg0KSW5mZXJlbmNlcyBmcm9tIHRoZSBhYm92ZSBjaGFydDoNCiAgMS4gTW9zdCBwZW9wbGUgd2hvIGFyZSBjdXJyZW50bHkgZW1wbG95ZWQgZnVsbCB0aW1lIG9yIHBhcnQgdGltZSBob3BlIHRvIGVpdGhlciB3b3JrIGluIGEgZGlmZmVyZW50L21vcmUgc3BlY2lhbGl6ZWQgcm9sZSBpbiBmaXZlIHllYXJzIG9yIHdhbnQgdG8gZmluZCB0aGVpciBvd24gY29tcGFueS4NCiAgMi4gTW9zdCBwZW9wbGUgd2hvIGFyZSBzZWxmLWVtcGxveWVkIG9yIGluZGVwZW5kZW50IGNvbnRyYWN0b3JzIGhvcGUgdG8gYmUgYSBmb3VuZGVyL2NvLWZvdW5kZXIgb2YgdGhlaXIgb3duIGNvbXBhbnkgb3IgZXhwZWN0IHRvIGJlIGRvaW5nIHRoZSBzYW1lIHdvcmsgaW4gZml2ZSB5ZWFycywgd2hpY2ggc2hvd3MgdGhhdCBwZW9wbGUgd2hvIGFyZSBzZWxmLWVtcGxveWVkIG9yIGluZGVwZW5kZW50IGNvbnRyYWN0b3JzIGFyZSBtb3JlIHNhdGlzZmllZCB3aXRoIHRoZWlyIGpvYi4NCiAgMy4gSXQgaXMgc3VycHJpc2luZyB0aGF0IHBlb3BsZSB3aG8gYXJlIGN1cnJlbnRseSBub3QgbG9va2luZyBmb3Igd29yayBob3BlIHRvIGJlIHdvcmtpbmcgaW4gZml2ZSB5ZWFycy4gDQogIA0KTGV0IHVzIGxvb2sgYXQgdGhlIGpvYi1zYXRpc2ZhY3Rpb24gYWNjb3JkaW5nIHRvIGN1cnJlbnQgZW1wbG95bWVudCBTdGF0dXMNCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKEVtcGxveW1lbnQpKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShKb2JTYXRpc2ZhY3Rpb24pKSAlPiUNCiAgY291bnQoRW1wbG95bWVudCxKb2JTYXRpc2ZhY3Rpb24pICU+JQ0KICBoY2hhcnQoImFyZWEiLGhjYWVzKHg9Sm9iU2F0aXNmYWN0aW9uLHk9bixncm91cD1FbXBsb3ltZW50KSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IkN1cnJlbnQgRW1wbG95bWVudCB2cyBKb2IgU2F0aXNmYWN0aW9uIixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkgJT4lDQogIGhjX3lBeGlzKHRpdGxlPWxpc3QodGV4dD0iTm8uIG9mIHJlc3BvbmRlbnRzIixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9IkpvYiBTYXRpc2ZhY3Rpb24iLHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSkgJT4lDQogIGhjX2FkZF90aGVtZShoY190aGVtZV9mbGF0KCkpDQpgYGANCg0KRnJvbSB0aGUgYWJvdmUgYXJlYSBjaGFydCwgd2UgY2FuIHNlZSB0aGF0IG1ham9yaXR5IG9mIHRoZSByZXNwb25kZW50cyBhcmUgZWl0aGVyIGV4dHJlbWVseSBvciBtb2RlcmF0ZWx5IHNhdGlzZmllZCB3aXRoIHRoZWlyIGpvYnMsIHdoaWxlIG9ubHkgYSB2ZXJ5IGxpdHRsZSBwZXJjZW50YWdlIG9mIHJlc3BvbmRlbnRzIGFyZSBleHRyZW1lbHkgZGlzc2F0aXNmaWVkIHdpdGggdGhlaXIgam9iLiANCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKEhvcGVGaXZlWWVhcnMpKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShKb2JTYXRpc2ZhY3Rpb24pKSAlPiUNCiAgY291bnQoSG9wZUZpdmVZZWFycyxKb2JTYXRpc2ZhY3Rpb24pICU+JQ0KICBoY2hhcnQoImhlYXRtYXAiLGhjYWVzKHg9Sm9iU2F0aXNmYWN0aW9uLHk9SG9wZUZpdmVZZWFycyx2YWx1ZT1uKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IkhvcGUgaW4gRml2ZSBZZWFycyB2cyBKb2IgU2F0aXNmYWN0aW9uIixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkgJT4lDQogIGhjX3lBeGlzKHRpdGxlPWxpc3QodGV4dD0iSG9wZSBpbiBGaXZlIHllYXJzIixzdHlsZT1saXN0KGZvbnRXZWlnaHQ9ImJvbGQiKSkpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9IkpvYiBTYXRpc2ZhY3Rpb24iLHN0eWxlPWxpc3QoZm9udFdlaWdodD0iYm9sZCIpKSkgJT4lDQogIGhjX2FkZF90aGVtZShoY190aGVtZV9nb29nbGUoKSkgDQpgYGANClRoZSBhYm92ZSBoZWF0IG1hcCBzaG93cyB1cyB0aGF0IG1vc3QgcGVvcGxlIHdobyBhcmUgY3VycmVudGx5IHNhdGlzZmllZCB3aXRoIHRoZWlyIGpvYnMgZXhwZWN0IHRvIGJlIGluIGEgaGlnaGVyIHJvbGUgb3Igc3RhcnQgdGhlaXIgb3duIGNvbXBhbmllcy4NCg0KUGFydCBJSTogRGV2ZWxvcGVyIFR5cGVzLCBZZWFycyBzcGVudCBjb2RpbmcsIFByZWZlcnJlZCBMYW5ndWFnZXMsSURFcywgRnJhbWV3b3JrcyBhbmQgQ29tcGFueSBTaXplLg0KDQpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgdHlwZSBvZiBEZXZlbG9wZXJzIHdobyB0b29rIHBhcnQgaW4gdGhlIHN1cnZleQ0KYGBge3J9DQpzdXJ2ZXkgJT4lDQogIGZpbHRlcighaXMubmEoRGV2VHlwZSkpICU+JQ0KICBzZWxlY3QoRGV2VHlwZSklPiUNCiAgbXV0YXRlKERldlR5cGU9c3RyX3NwbGl0KERldlR5cGUsIjsiKSkgJT4lDQogIHVubmVzdChEZXZUeXBlKSAlPiUNCiAgZ3JvdXBfYnkoRGV2VHlwZSkgJT4lDQogIGNvdW50KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSktPnQNCnQkbjwtIHJvdW5kKCh0JG4vc2l6ZSkqMTAwLDIpDQpoaWdoY2hhcnQoKSAlPiUNCiAgaGNfYWRkX3Nlcmllcyh0LHR5cGUgPSAiYmFyIiwgaGNhZXMoeCA9IkRldlR5cGUiLCB5ID0gIm4iKSwgZGF0YUxhYmVscyA9IGxpc3QoZW5hYmxlZCA9IFRSVUUpKSAlPiUNCiAgaGNfbGVnZW5kKGVuYWJsZWQ9RkFMU0UpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJEZXZlbG9wZXIgVHlwZXMgb2YgUmVzcG9uZGVudHMiKSAlPiUNCiAgaGNfeEF4aXMoY2F0ZWdvcmllcz10JERldlR5cGUpICU+JSANCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJQZXJjZW50YWdlIG9mIFJlc3BvbmRlbnRzIikpICU+JQ0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfdHVmdGUoKSkgJT4lDQogIGhjX2NvbG9ycygib3JhbmdlIikNCmBgYA0KV2UgY2FuIHNlZSB0aGF0IGEgc3RhZ2dlcmluZyA1My45MiUgb2YgcmVzcG9uZGVudHMgYXJlIEJhY2stZW5kIERldmVsb3BlcnMgYW5kIDQ0Ljg3JSBvZiByZXNwb25kZW50cyBhcmUgRnVsbC1TdGFjayBEZXZlbG9wZXJzLCB3aGVyZWFzIEZyb250LWVuZCBkZXZlbG9wZXJzIGFyZSB0aGlyZCBtb3N0IHdpdGggMzUuMjMlLiBXaGlsZSBEYXRhIFNjaWVudGlzdHMgYW5kIERhdGEgYW5hbHlzdHMgYXJlIGNvbnNpZGVyZWQgdGhlIGhvdHRlc3QgcHJvc3BlY3Qgb2Ygam9icywgaXQgaXMgYSBiaXQgc3VycHJpc2luZyB0byBzZWUgdGhhdCBvbmx5IDcuMTclIGFuZCA3LjY1JSBvZiB0aGVtIGhhdmUgdGFrZW4gdGhlIHN1cnZleS4NCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgaG93IG1hbnkgeWVhcnMgdGhlIHJlc3BvbmRlbnRzIGhhdmUgc3BlbnQgY29kaW5nLg0KDQpgYGB7cn0NCnN1cnZleSAlPiUNCiAgZmlsdGVyKCFpcy5uYShZZWFyc0NvZGluZykpICU+JQ0KICBncm91cF9ieShZZWFyc0NvZGluZykgJT4lDQogIGNvdW50KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSktPnQNCmhpZ2hjaGFydCgpICU+JQ0KICBoY19hZGRfc2VyaWVzKHQsdHlwZSA9ICJjb2x1bW4iLCBoY2Flcyh4ID0iWWVhcnNDb2RpbmciLCB5ID0gIm4iKSwgZGF0YUxhYmVscyA9IGxpc3QoZW5hYmxlZCA9IFRSVUUpKSAlPiUNCiAgaGNfbGVnZW5kKGVuYWJsZWQ9RkFMU0UpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJIb3cgbWFueSB5ZWFycyBoYXZlIHJlc3BvbmRlbnRzIHNwZW50IGNvZGluZz8iKSAlPiUNCiAgaGNfeEF4aXModGl0bGU9bGlzdCh0ZXh0PSJZZWFycyIpLGNhdGVnb3JpZXM9dCRZZWFyc0NvZGluZykgJT4lIA0KICBoY195QXhpcyh0aXRsZT1saXN0KHRleHQ9Ik5vLiBvZiByZXNwb25kZW50cyIpKSAlPiUNCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX3R1ZnRlKCkpICU+JQ0KICBoY19jb2xvcnMoImJsdWUiKQ0KYGBgDQpNb3N0IG9mIHRoZSByZXNwb25kZW50cyBoYXZlIHNwZW50IGNvZGluZyBmb3IgMy01IHllYXJzIHdoaWxlIHRoZSBzZWNvbmQgYW5kIHRoaXJkLW1vc3QgYXJlIHJlc3BvbmRlbnRzIHdobyBoYXZlIHNwZW50IGNvZGluZyBmb3IgNi04IHllYXJzIGFuZCA5LTExIHllYXJzLiBXaGF0IGlzIG1vc3Qgc3VycHJpc2luZyB0byBzZWUgaXMgdGhhdCBtb3JlIHRoYW4gODAwMCByZXNwb25kZW50cyh+OSUpIGhhdmUgY29kZWQgZm9yIG1vcmUgdGhhbiAyMCB5ZWFycyBhbmQgc3RpbGwgY29udHJpYnV0ZSB0byB0aGUgU3RhY2tPdmVyZmxvdyBDb21tdW5pdHkuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBmaWx0ZXIoIWlzLm5hKFllYXJzQ29kaW5nUHJvZikpICU+JQ0KICBncm91cF9ieShZZWFyc0NvZGluZ1Byb2YpICU+JQ0KICBjb3VudCgpICU+JQ0KICBhcnJhbmdlKGRlc2MobikpLT50DQpoaWdoY2hhcnQoKSAlPiUNCiAgaGNfYWRkX3Nlcmllcyh0LHR5cGUgPSAiY29sdW1uIiwgaGNhZXMoeCA9IlllYXJzQ29kaW5nUHJvZiIsIHkgPSAibiIpLCBkYXRhTGFiZWxzID0gbGlzdChlbmFibGVkID0gVFJVRSkpICU+JQ0KICBoY19sZWdlbmQoZW5hYmxlZD1GQUxTRSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IkhvdyBtYW55IHllYXJzIGhhdmUgcmVzcG9uZGVudHMgc3BlbnQgY29kaW5nIHByb2Zlc3Npb25hbGx5PyIpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9IlllYXJzIiksY2F0ZWdvcmllcz10JFllYXJzQ29kaW5nUHJvZikgJT4lIA0KICBoY195QXhpcyh0aXRsZT1saXN0KHRleHQ9Ik5vLiBvZiByZXNwb25kZW50cyIpKSAlPiUNCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX3R1ZnRlKCkpICU+JQ0KICBoY19jb2xvcnMoImJsdWUiKQ0KYGBgDQoNCldoaWxlIG1vc3QgcmVzcG9uZGVudHMgaGF2ZSBjb2RlZCBmb3IgMy01IHllYXJzIGFuZCA2LTggeWVhcnMgYXMgc2VlbiBpbiB0aGUgcHJldmlvdXMgcGxvdCwgYSBtYWpvcml0eSBvZiB0aGVtIGhhdmUgY29kZWQgcHJvZmVzc2lvbmFsbHkgZm9yIG9ubHkgbGVzcyB0aGFuIDUgeWVhcnMuIFRoaXMgY2FuIGluZGljYXRlIG9uZSBvZiB0aGUgZm9sbG93aW5nIHRoaW5nczoNCg0KMS4gQSBsb3Qgb2YgcGVvcGxlIG9mIHN0YXJ0IGNvZGluZyBkdXJpbmcgdGhlaXIgY29sbGVnZSB5ZWFycyBhbmQgY29udGludWUgdG8gY29kZSBwcm9mZXNzaW9uYWxseS4NCjIuIEEgbG90IG9mIHBlb3BsZSBzdGFydCBjb2Rpbmcgb25seSB3aGVuIHRoZXkgZ2V0IGEgam9iLg0KTGV0IHVzIHRha2UgYSBsb29rIGF0IHRoZSBmb2xsb3dpbmcgcGxvdCB0byB1bmRlcnN0YW5kIG1vcmUuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBjb3VudChZZWFyc0NvZGluZyxZZWFyc0NvZGluZ1Byb2YpICU+JQ0KICBoY2hhcnQoImhlYXRtYXAiLGhjYWVzKHg9WWVhcnNDb2RpbmcseT1ZZWFyc0NvZGluZ1Byb2YsdmFsdWU9bikpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJZZWFycyBDb2RlZCB2cyBZZWFycyBDb2RpbmcgUHJvZmVzc2lvbmFsbHkiKSAlPiUNCiAgaGNfeEF4aXModGl0bGU9bGlzdCh0ZXh0PSJZZWFycyBDb2RlZCIpKSAlPiUgDQogIGhjX3lBeGlzKHRpdGxlPWxpc3QodGV4dD0iWWVhcnMgQ29kaW5nIFByb2Zlc3Npb25hbGx5IikpDQpgYGANCkFzIHdlIGNhbiBzZWUsDQoxLiBNb3N0IHBlb3BsZSB3aG8gaGF2ZSBjb2RlZCBmb3IgMC0yIHllYXJzIGhhdmUgY29kZWQgb25seSBwcm9mZXNzaW9uYWxseS4NCjIuIE1ham9yaXR5IG9mIHBlb3BsZSB3aG8gaGF2ZSBjb2RlZCBmb3IgMy01IGhhdmUgYWxzbyBjb2RlZCBwcm9mZXNzaW9uYWxseSBmb3IgMy01IHllYXJzLg0KMy4gQSBsb3Qgb2YgcGVvcGxlIHdobyBoYXZlIGNvZGVkIGZvciA2LTggeWVhcnMgaGF2ZSBhbHNvIGNvZGVkIHByb2Zlc3Npb25hbGx5IGZvciA2LTggeWVhcnMuDQpBbGwgb2YgdGhpcyBpbmRpY2F0ZXMgdGhhdCBhIG1ham9yaXR5IG9mIHBlb3BsZSBoYXZlIG9ubHkgZXZlciBjb2RlZCBwcm9mZXNzaW9uYWxseSB3aGljaCBtZWFucyB0aGV5IGhhdmUgYmVndW4gY29kaW5nIG9ubHkgYWZ0ZXIgZ2V0dGluZyBvciBzdGFydGluZyBhIGpvYi4NCg0KV2UgY2FuIGFsc28gc2VlIHRoZSBuZXh0IG1ham9yaXR5IG9mIHBlb3BsZSB3aG8gaGF2ZSBjb2RlZCBmb3IgMy01IHllYXJzLCA2LTggeWVhcnMgYW5kIDktMTEgeWVhcnMgaGF2ZSBjb2RlZCBwcm9mZXNzaW9uYWxseSBmb3IgMC0yIHllYXJzLDMtNSB5ZWFycyBhbmQgNi04IHllYXJzIHByb2Zlc3Npb25hbGx5LiBUSGlzIG1vc3QgcHJvYmFibHkgaW5kaWNhdGVzIHRoYXQgcmVzcG9uZGVudHMgc3RhcnQgY29kaW5nIHdoaWxlIGluIGNvbGxlZ2UgYW5kIHN0YXJ0IGNvZGluZyBwcm9mZXNzaW9uYWxseSBpbW1lZGlhdGVseSBhZnRlciBncmFkdWF0aW9uLg0KDQpOb3csIExldCB1cyB0YWtlIGEgbG9vayBhdCB0aGUgTGFuZ3VhZ2VzLCBGcmFtZXdvcmtzIGFuZCBJREVzIHVzZWQgYnkgRGV2ZWxvcGVycy4NCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KIGZpbHRlcighaXMubmEoTGFuZ3VhZ2VXb3JrZWRXaXRoKSkgJT4lDQogIHNlbGVjdChMYW5ndWFnZVdvcmtlZFdpdGgpICU+JQ0KICBtdXRhdGUoTGFuZ3VhZ2VXb3JrZWRXaXRoID0gc3RyX3NwbGl0KExhbmd1YWdlV29ya2VkV2l0aCwgcGF0dGVybiA9ICI7IikpICU+JQ0KICB1bm5lc3QoTGFuZ3VhZ2VXb3JrZWRXaXRoKSAlPiUNCiAgZ3JvdXBfYnkoTGFuZ3VhZ2VXb3JrZWRXaXRoKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKSAtPnQNCnQkbiA8LSByb3VuZCgodCRuL3NpemUpKjEwMCwyKQ0KaGlnaGNoYXJ0KCkgJT4lDQpoY19hZGRfc2VyaWVzKHQsdHlwZT0iYmFyIixoY2Flcyh4PSJMYW5ndWFnZVdvcmtlZFdpdGgiLHk9Im4iKSxkYXRhTGFiZWxzID0gbGlzdChlbmFibGVkID0gVFJVRSkpICU+JSANCiAgaGNfbGVnZW5kKGVuYWJsZWQ9RkFMU0UpICU+JQ0KICBoY19jb2xvcnMoInJlZCIpICU+JSANCiAgaGNfdGl0bGUodGV4dCA9ICdMYW5nYXVhZ2VzIERldmVsb3BlcnMgSGF2ZSBXb3JrZWQgV2l0aCcpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9Ikxhbmd1YWdlIFdvcmtlZCBXaXRoIiksY2F0ZWdvcmllcz10JExhbmd1YWdlV29ya2VkV2l0aCkgJT4lIA0KICBoY195QXhpcyh0aXRsZT1saXN0KHRleHQ9IlBlcmNlbnRhZ2UiKSxsYWJlbHMgPSBsaXN0KGZvcm1hdCA9ICJ7dmFsdWV9JSIpKQ0KYGBgDQoNCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KIGZpbHRlcighaXMubmEoTGFuZ3VhZ2VXb3JrZWRXaXRoKSkgJT4lDQogIHNlbGVjdChMYW5ndWFnZVdvcmtlZFdpdGgpICU+JQ0KICBtdXRhdGUoTGFuZ3VhZ2VXb3JrZWRXaXRoID0gc3RyX3NwbGl0KExhbmd1YWdlV29ya2VkV2l0aCwgcGF0dGVybiA9ICI7IikpICU+JQ0KICB1bm5lc3QoTGFuZ3VhZ2VXb3JrZWRXaXRoKSAlPiUNCiAgZ3JvdXBfYnkoTGFuZ3VhZ2VXb3JrZWRXaXRoKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUNCiAgaGNoYXJ0KCJ0cmVlbWFwIixoY2Flcyh4PUxhbmd1YWdlV29ya2VkV2l0aCx2YWx1ZT1uLGNvbG9yPW4pKSAlPiUNCiAgaGNfY29sb3JBeGlzKHN0b3BzPWNvbG9yX3N0b3BzKGNvbG9ycz12aXJpZGlzKDEwKSkpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJMYW5ndWFnZXMgRGV2ZWxvcGVycyBIYXZlIFdvcmtlZCBXaXRoIikNCmBgYA0KDQoNClRvcCBMYW5ndWFnZXMgRGV2ZWxvcGVycyBoYXZlIHdvcmtlZCB3aXRoOg0KSmF2YVNjcmlwdCA6IDU1LjMyJQ0KSFRNTCA6IDU0LjI1JQ0KQ1NTIDogNTEuNTclDQpTUUwgOiA0NS4xOSUNCkphdmEgOiAzNS45MyUNCkJhc2gvU2hlbGwgOiAzMS41MyUNClB5dGhvbiA6IDMwLjcxICUNCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KIGZpbHRlcighaXMubmEoTGFuZ3VhZ2VEZXNpcmVOZXh0WWVhcikpICU+JQ0KICBzZWxlY3QoTGFuZ3VhZ2VEZXNpcmVOZXh0WWVhcikgJT4lDQogIG11dGF0ZShMYW5ndWFnZURlc2lyZU5leHRZZWFyID0gc3RyX3NwbGl0KExhbmd1YWdlRGVzaXJlTmV4dFllYXIsIHBhdHRlcm4gPSAiOyIpKSAlPiUNCiAgdW5uZXN0KExhbmd1YWdlRGVzaXJlTmV4dFllYXIpICU+JQ0KICBncm91cF9ieShMYW5ndWFnZURlc2lyZU5leHRZZWFyKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKSAtPnQNCnQkbiA8LSByb3VuZCgodCRuL3NpemUpKjEwMCwyKQ0KaGlnaGNoYXJ0KCkgJT4lDQpoY19hZGRfc2VyaWVzKHQsdHlwZT0iYmFyIixoY2Flcyh4PSJMYW5ndWFnZURlc2lyZU5leHRZZWFyIix5PSJuIiksZGF0YUxhYmVscyA9IGxpc3QoZW5hYmxlZCA9IFRSVUUpKSAlPiUgDQogIGhjX2xlZ2VuZChlbmFibGVkPUZBTFNFKSAlPiUNCiAgaGNfY29sb3JzKCJibHVlIikgJT4lIA0KICBoY190aXRsZSh0ZXh0ID0gJ0xhbmdhdWFnZXMgRGV2ZWxvcGVycyBXYW50IHRvIFdvcmsgV2l0aCcpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9Ikxhbmd1YWdlIiksY2F0ZWdvcmllcz10JExhbmd1YWdlRGVzaXJlTmV4dFllYXIpICU+JSANCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJQZXJjZW50YWdlIiksbGFiZWxzID0gbGlzdChmb3JtYXQgPSAie3ZhbHVlfSUiKSkNCmBgYA0KDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JSANCiBmaWx0ZXIoIWlzLm5hKExhbmd1YWdlRGVzaXJlTmV4dFllYXIpKSAlPiUNCiAgc2VsZWN0KExhbmd1YWdlRGVzaXJlTmV4dFllYXIpICU+JQ0KICBtdXRhdGUoTGFuZ3VhZ2VEZXNpcmVOZXh0WWVhciA9IHN0cl9zcGxpdChMYW5ndWFnZURlc2lyZU5leHRZZWFyLCBwYXR0ZXJuID0gIjsiKSkgJT4lDQogIHVubmVzdChMYW5ndWFnZURlc2lyZU5leHRZZWFyKSAlPiUNCiAgZ3JvdXBfYnkoTGFuZ3VhZ2VEZXNpcmVOZXh0WWVhcikgJT4lDQogIGNvdW50KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogIGhjaGFydCgidHJlZW1hcCIsaGNhZXMoeD1MYW5ndWFnZURlc2lyZU5leHRZZWFyLHZhbHVlPW4sY29sb3I9bikpICU+JQ0KICBoY19jb2xvckF4aXMoc3RvcHM9Y29sb3Jfc3RvcHMoY29sb3JzPXZpcmlkaXMoMTApKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9Ikxhbmd1YWdlcyBEZXZlbG9wZXJzIFdhbnQgdG8gV29yayBXaXRoIikNCmBgYA0KDQpNb3N0IG9mIGRldmVsb3BlcnMgd2FudCB0byBjb250aW51ZSB3b3JraW5nIHdpdGggSmF2YVNjcmlwdCwgSFRNTCBhbmQgQ1NTLCBTUUwgYW5kIEJhc2gvU2hlbGwuDQozMy4xNyUgb2YgRGV2ZWxvcGVycyB3b3VsZCBsaWtlIHRvIHdvcmsgd2l0aCBQeXRob24uDQpMYW5ndWFnZXMgdGhhdCBkZXZlbG9wZXJzIGN1cnJlbnRseSBkb24ndCB3b3JrIHdpdGggYSBsb3QgYnV0IHdvdWxkIGxpa2UgdG8gd29yayB3aXRoIGFyZSBDKyssQyMsS290bGluLFN3aWZ0Lg0KDQpUaGUgdHJlZSBtYXBzIGdpdmUgYSBiZXR0ZXIgdmlzdWFsaXphdGlvbiBvZiBMYW5ndWFnZXMgV29ya2VkIFdpdGggYnkgZGV2ZWxvcGVycyBhbmQgTGFuZ3VhZ2VzIHRoZXkgZGVzaXJlIHRvIHdvcmsgd2l0aC4NCg0KTm93LCBsZXQgdXMgdGFrZSBhIGxvb2sgYXQgd2hhdCBsYW5ndWFnZXMgcGVvcGxlIHdobyBoYXZlIGp1c3QgYmVndW4gY29kaW5nIGxlYXJuLg0KDQpgYGB7cn0NCnN1cnZleSAlPiUgDQogIGZpbHRlcighaXMubmEoTGFuZ3VhZ2VXb3JrZWRXaXRoKSkgJT4lDQogIGZpbHRlcighaXMubmEoWWVhcnNDb2RpbmcpLCBZZWFyc0NvZGluZyAlaW4lIGMoIjAtMiB5ZWFycyIpKSAlPiUNCiAgc2VsZWN0KExhbmd1YWdlV29ya2VkV2l0aCkgJT4lDQogIG11dGF0ZShMYW5ndWFnZVdvcmtlZFdpdGggPSBzdHJfc3BsaXQoTGFuZ3VhZ2VXb3JrZWRXaXRoLCBwYXR0ZXJuID0gIjsiKSkgJT4lDQogIHVubmVzdChMYW5ndWFnZVdvcmtlZFdpdGgpICU+JQ0KICBncm91cF9ieShMYW5ndWFnZVdvcmtlZFdpdGgpICU+JQ0KICBjb3VudCgpICU+JQ0KICBhcnJhbmdlKGRlc2MobikpIC0+dA0KaGlnaGNoYXJ0KCkgJT4lDQpoY19hZGRfc2VyaWVzKHQsdHlwZT0iYmFyIixoY2Flcyh4PSJMYW5ndWFnZVdvcmtlZFdpdGgiLHk9Im4iKSxkYXRhTGFiZWxzID0gbGlzdChlbmFibGVkID0gVFJVRSkpICU+JSANCiAgaGNfbGVnZW5kKGVuYWJsZWQ9RkFMU0UpICU+JQ0KICBoY19jb2xvcnMoImJsdWUiKSAlPiUgDQogIGhjX3RpdGxlKHRleHQgPSAnTGFuZ2F1YWdlcyBEZXZlbG9wZXJzIHdobyBoYXZlIDAtMiB5ZWFycyBjb2RpbmcgZXhwZXJpZW5jZSBoYXZlIHdvcmtlZCB3aXRoJykgJT4lDQogIGhjX3hBeGlzKHRpdGxlPWxpc3QodGV4dD0iTGFuZ3VhZ2UiKSxjYXRlZ29yaWVzPXQkTGFuZ3VhZ2VXb3JrZWRXaXRoKSAlPiUgDQogIGhjX3lBeGlzKHRpdGxlPWxpc3QodGV4dD0iTm8uIG9mIHJlc3BvbmRlbnRzIikpDQpgYGANCg0KVGhpcyBzaG93cyB0aGF0IGEgbG90IG9mIHBlb3BsZSB3aG8gaGF2ZSBqdXN0IGJlZ3VuIGNvZGluZyBzdGFydCB3aXRoIEhUTUwvQ1NTICwgSmF2YVNjcmlwdCwgU1FMIGFuZCBKYXZhLg0KDQoNCkxldCB1cyBub3cgdGFrZSBhIGxvb2sgYXQgSURFIFByZWZlcmVuY2VzIG9mIERldmVsb3BlcnMuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JSANCiBmaWx0ZXIoIWlzLm5hKElERSkpICU+JQ0KICBzZWxlY3QoSURFKSAlPiUNCiAgbXV0YXRlKElERSA9IHN0cl9zcGxpdChJREUsIHBhdHRlcm4gPSAiOyIpKSAlPiUNCiAgdW5uZXN0KElERSkgJT4lDQogIGdyb3VwX2J5KElERSkgJT4lDQogIGNvdW50KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgLT50DQp0JG4gPC0gcm91bmQoKHQkbi9zaXplKSoxMDAsMikNCmhpZ2hjaGFydCgpICU+JQ0KaGNfYWRkX3Nlcmllcyh0LHR5cGU9ImJhciIsaGNhZXMoeD0iSURFIix5PSJuIiksZGF0YUxhYmVscyA9IGxpc3QoZW5hYmxlZCA9IFRSVUUpKSAlPiUgDQogIGhjX2xlZ2VuZChlbmFibGVkPUZBTFNFKSAlPiUNCiAgaGNfY29sb3JzKCJvcmFuZ2UiKSAlPiUgDQogIGhjX3RpdGxlKHRleHQgPSAnSURFIFByZWZlcmVuY2VzIG9mIERldmVsb3BlcnMnKSAlPiUNCiAgaGNfeEF4aXModGl0bGU9bGlzdCh0ZXh0PSJJREUiKSxjYXRlZ29yaWVzPXQkSURFKSAlPiUgDQogIGhjX3lBeGlzKHRpdGxlPWxpc3QodGV4dD0iUGVyY2VudGFnZSIpLGxhYmVscyA9IGxpc3QoZm9ybWF0ID0gInt2YWx1ZX0lIikpDQpgYGANCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KIGZpbHRlcighaXMubmEoSURFKSkgJT4lDQogIHNlbGVjdChJREUpICU+JQ0KICBtdXRhdGUoSURFID0gc3RyX3NwbGl0KElERSwgcGF0dGVybiA9ICI7IikpICU+JQ0KICB1bm5lc3QoSURFKSAlPiUNCiAgZ3JvdXBfYnkoSURFKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUNCiAgaGNoYXJ0KCJ0cmVlbWFwIixoY2Flcyh4PUlERSx2YWx1ZT1uLGNvbG9yPW4pKSAlPiUNCiAgaGNfY29sb3JBeGlzKHN0b3BzPWNvbG9yX3N0b3BzKGNvbG9ycz1wbGFzbWEoMTApKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IklERSBQcmVmZXJlbmNlcyBvZiBEZXZlbG9wZXJzIikNCmBgYA0KDQpNYWpvcml0eSBvZiBEZXZlbG9wZXJzIHByZWZlciBWaXN1YWwgU3R1ZGlvIENvZGUsIFZpc3VhbCBTdHVkaW8gYW5kIE5vdGVwYWQrKyB3aGlsZSBTdWJsaW1lIFRleHQsIFZpbSBhbmQgSW50ZWxsaUogcmVtYWluIHBvcHVsYXIgb3B0aW9ucy4NCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KIGZpbHRlcighaXMubmEoRnJhbWV3b3JrV29ya2VkV2l0aCkpICU+JQ0KICBzZWxlY3QoRnJhbWV3b3JrV29ya2VkV2l0aCkgJT4lDQogIG11dGF0ZShGcmFtZXdvcmtXb3JrZWRXaXRoID0gc3RyX3NwbGl0KEZyYW1ld29ya1dvcmtlZFdpdGgsIHBhdHRlcm4gPSAiOyIpKSAlPiUNCiAgdW5uZXN0KEZyYW1ld29ya1dvcmtlZFdpdGgpICU+JQ0KICBncm91cF9ieShGcmFtZXdvcmtXb3JrZWRXaXRoKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKSAtPnQNCnQkbiA8LSByb3VuZCgodCRuL3NpemUpKjEwMCwyKQ0KaGlnaGNoYXJ0KCkgJT4lDQpoY19hZGRfc2VyaWVzKHQsdHlwZT0iYmFyIixoY2Flcyh4PSJGcmFtZXdvcmtXb3JrZWRXaXRoIix5PSJuIiksZGF0YUxhYmVscyA9IGxpc3QoZW5hYmxlZCA9IFRSVUUpKSAlPiUgDQogIGhjX2xlZ2VuZChlbmFibGVkPUZBTFNFKSAlPiUNCiAgaGNfY29sb3JzKCJncmVlbiIpICU+JSANCiAgaGNfdGl0bGUodGV4dCA9ICdGcmFtZXdvcmsgRGV2ZWxvcGVycyBIYXZlIFdvcmtlZCBXaXRoJykgJT4lDQogIGhjX3hBeGlzKHRpdGxlPWxpc3QodGV4dD0iRnJhbWV3b3JrIiksY2F0ZWdvcmllcz10JEZyYW1ld29ya1dvcmtlZFdpdGgpICU+JSANCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJQZXJjZW50YWdlIiksbGFiZWxzID0gbGlzdChmb3JtYXQgPSAie3ZhbHVlfSUiKSkNCmBgYA0KDQpgYGB7cn0NCnN1cnZleSAlPiUgDQogZmlsdGVyKCFpcy5uYShGcmFtZXdvcmtXb3JrZWRXaXRoKSkgJT4lDQogIHNlbGVjdChGcmFtZXdvcmtXb3JrZWRXaXRoKSAlPiUNCiAgbXV0YXRlKEZyYW1ld29ya1dvcmtlZFdpdGggPSBzdHJfc3BsaXQoRnJhbWV3b3JrV29ya2VkV2l0aCwgcGF0dGVybiA9ICI7IikpICU+JQ0KICB1bm5lc3QoRnJhbWV3b3JrV29ya2VkV2l0aCkgJT4lDQogIGdyb3VwX2J5KEZyYW1ld29ya1dvcmtlZFdpdGgpICU+JQ0KICBjb3VudCgpICU+JQ0KICBhcnJhbmdlKGRlc2MobikpICU+JQ0KICBoY2hhcnQoInRyZWVtYXAiLGhjYWVzKHg9RnJhbWV3b3JrV29ya2VkV2l0aCx2YWx1ZT1uLGNvbG9yPW4pKSAlPiUNCiAgaGNfY29sb3JBeGlzKHN0b3BzPWNvbG9yX3N0b3BzKGNvbG9ycz1pbmZlcm5vKDEwKSkpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJGcmFtZXdvcmtzIERldmVsb3BlcnMgSGF2ZSBXb3JrZWQgV2l0aCIpDQpgYGANCg0KQ29uc2lkZXJpbmcgdGhhdCBtb3N0IHBlb3BsZSBoYXZlIHdvcmtlZCB3aXRoIEphdmFTY3JpcHQsSFRNTCBhbmQgQ1NTLCBOb2RlLmpzLCBBbmd1bGFyIGFuZCBSZWFjdCBhcmUgdGhlIG1vc3QgcG9wdWxhciBGcmFtZXdvcmtzIGRldmVsb3BlcnMgaGF2ZSB3b3JrZWQgd2l0aCBhcyB0aGV5IGFyZSBhbGwgcmVsYXRlZCB0byB3ZWIgZGV2ZWxvcG1lbnQuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JSANCiBmaWx0ZXIoIWlzLm5hKEZyYW1ld29ya0Rlc2lyZU5leHRZZWFyKSkgJT4lDQogIHNlbGVjdChGcmFtZXdvcmtEZXNpcmVOZXh0WWVhcikgJT4lDQogIG11dGF0ZShGcmFtZXdvcmtEZXNpcmVOZXh0WWVhciA9IHN0cl9zcGxpdChGcmFtZXdvcmtEZXNpcmVOZXh0WWVhciwgcGF0dGVybiA9ICI7IikpICU+JQ0KICB1bm5lc3QoRnJhbWV3b3JrRGVzaXJlTmV4dFllYXIpICU+JQ0KICBncm91cF9ieShGcmFtZXdvcmtEZXNpcmVOZXh0WWVhcikgJT4lDQogIGNvdW50KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgLT50DQp0JG4gPC0gcm91bmQoKHQkbi9zaXplKSoxMDAsMikNCmhpZ2hjaGFydCgpICU+JQ0KaGNfYWRkX3Nlcmllcyh0LHR5cGU9ImJhciIsaGNhZXMoeD0iRnJhbWV3b3JrRGVzaXJlTmV4dFllYXIiLHk9Im4iKSxkYXRhTGFiZWxzID0gbGlzdChlbmFibGVkID0gVFJVRSkpICU+JSANCiAgaGNfbGVnZW5kKGVuYWJsZWQ9RkFMU0UpICU+JQ0KICBoY19jb2xvcnMoImdyZWVuIikgJT4lIA0KICBoY190aXRsZSh0ZXh0ID0gJ0ZyYW1ld29yayBEZXZlbG9wZXJzIFdhbnQgdG8gV29yayBXaXRoJykgJT4lDQogIGhjX3hBeGlzKHRpdGxlPWxpc3QodGV4dD0iRnJhbWV3b3JrIiksY2F0ZWdvcmllcz10JEZyYW1ld29ya0Rlc2lyZU5leHRZZWFyKSAlPiUgDQogIGhjX3lBeGlzKHRpdGxlPWxpc3QodGV4dD0iUGVyY2VudGFnZSIpLGxhYmVscyA9IGxpc3QoZm9ybWF0ID0gInt2YWx1ZX0lIikpDQpgYGANCg0KYGBge3J9DQpzdXJ2ZXkgJT4lIA0KIGZpbHRlcighaXMubmEoRnJhbWV3b3JrRGVzaXJlTmV4dFllYXIpKSAlPiUNCiAgc2VsZWN0KEZyYW1ld29ya0Rlc2lyZU5leHRZZWFyKSAlPiUNCiAgbXV0YXRlKEZyYW1ld29ya0Rlc2lyZU5leHRZZWFyID0gc3RyX3NwbGl0KEZyYW1ld29ya0Rlc2lyZU5leHRZZWFyLCBwYXR0ZXJuID0gIjsiKSkgJT4lDQogIHVubmVzdChGcmFtZXdvcmtEZXNpcmVOZXh0WWVhcikgJT4lDQogIGdyb3VwX2J5KEZyYW1ld29ya0Rlc2lyZU5leHRZZWFyKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUNCiAgaGNoYXJ0KCJ0cmVlbWFwIixoY2Flcyh4PUZyYW1ld29ya0Rlc2lyZU5leHRZZWFyLHZhbHVlPW4sY29sb3I9bikpICU+JQ0KICBoY19jb2xvckF4aXMoc3RvcHM9Y29sb3Jfc3RvcHMoY29sb3JzPWluZmVybm8oMTApKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IkZyYW1ld29ya3MgRGV2ZWxvcGVycyB3YW50IHRvIFdvcmsgV2l0aCIpDQpgYGANCg0KTm9kZS5qcyBzdGlsbCByZW1haW5zIGF0IHRoZSB0b3AsIGJ1dCBtb3JlIGRldmVsb3BlcnMgd2FudCB0byBleHBsb3JlIFJlYWN0IGFuZCBBbmd1bGFyLiBUZW5zb3JGbG93IGlzIHRoZSBGcmFtZXdvcmsgdGhhdCBhIGxvdCBvZiBwZW9wbGUgaGF2ZW4ndCB3b3JrZWQgd2l0aCB5ZXQsIGJ1dCB3b3VsZCBsaWtlIHRvIHdvcmsgd2l0aCBhIGxvdC4gSSBiZWxpZXZlIHRoaXMgaXMgZHVlIHRvIGluY3JlYXNpbmcgTUwgcmVzZWFyY2ggYW5kIG9wcG9ydHVuaXRpZXMuDQoNCmBgYHtyfQ0Kc3VydmV5ICU+JSANCiBmaWx0ZXIoIWlzLm5hKE9wZXJhdGluZ1N5c3RlbSkpICU+JQ0KICBzZWxlY3QoT3BlcmF0aW5nU3lzdGVtKSAlPiUNCiAgbXV0YXRlKE9wZXJhdGluZ1N5c3RlbSA9IHN0cl9zcGxpdChPcGVyYXRpbmdTeXN0ZW0sIHBhdHRlcm4gPSAiOyIpKSAlPiUNCiAgdW5uZXN0KE9wZXJhdGluZ1N5c3RlbSkgJT4lDQogIGdyb3VwX2J5KE9wZXJhdGluZ1N5c3RlbSkgJT4lDQogIGNvdW50KCkgJT4lDQogIHBsb3RfbHkodHlwZT0icGllIiwNCiAgICAgICAgICBsYWJlbHM9fk9wZXJhdGluZ1N5c3RlbSwNCiAgICAgICAgICB2YWx1ZXM9fm4sDQogICAgICAgICAgdGV4dHBvc2l0aW9uPSJpbnNpZGUiLA0KICAgICAgICAgIHRleHRpbmZvPSdsYWJlbCtwZXJjZW50K3ZhbHVlJywNCiAgICAgICAgICBzaG93bGVnZW5kPUZBTFNFLA0KICAgICAgICAgIG1hcmtlcj1saXN0KGNvbG9ycyA9IHZpcmlkaXMoNCkpDQogICklPiUNCiAgICAgICAgICBsYXlvdXQodGl0bGU9Ik9wZXJhdGluZyBTeXN0ZW0gUHJlZmVybmNlIG9mIERldmVsb3BlcnMiKQ0KYGBgDQpXaW5kb3dzIHN0aWxsIHJlbWFpbnMgdGhlIHBvcHVsYXIgT3BlcmF0aW5nIFN5c3RlbSBEZXZlbG9wZXJzIHdvcmsgd2l0aC4NCg0KUGFydCBJSUk6IFNhbGFyeSBBbmFseXNpcw0KYGBge3IscmVzdWx0cz0naGlkZScsZmlnLmtlZXA9J2FsbCd9DQpzdXJ2ZXkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKENvdW50cnkpKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShDb252ZXJ0ZWRTYWxhcnkpKSAlPiUNCiAgZ3JvdXBfYnkoQ291bnRyeSkgJT4lDQogIHN1bW1hcmlzZShNZWRpYW5fc2FsYXJ5PW1lZGlhbihDb252ZXJ0ZWRTYWxhcnksbmEucm0gPSBUUlVFKSkgLT50DQpjb2RlIDwtIGNvdW50cnljb2RlKHQkQ291bnRyeSwgJ2NvdW50cnkubmFtZScsICdpc28zYycpDQp0JGlzbzMgPC0gY29kZQ0KaGlnaGNoYXJ0KCkgJT4lDQogICAgaGNfYWRkX3Nlcmllc19tYXAod29ybGRnZW9qc29uLCB0LCB2YWx1ZSA9ICJNZWRpYW5fc2FsYXJ5Iiwgam9pbkJ5ID0gImlzbzMiKSAlPiUNCiAgICBoY19jb2xvckF4aXMoc3RvcHM9Y29sb3Jfc3RvcHMoY29sb3JzPXdlc19wYWxldHRlKCJDYXZhbGNhbnRpMSIsIDEwLCB0eXBlID0gImNvbnRpbnVvdXMiKSkpICU+JQ0KICAgIGhjX3RpdGxlKHRleHQ9Ik1lZGlhbiBTYWxhcnkgb2YgQ291bnRyaWVzIikgJT4lDQogICAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2dvb2dsZSgpKQ0KDQogICAgDQpgYGANCg0KYGBge3J9DQpzdXJ2ZXkgJT4lDQogIGZpbHRlcihFbXBsb3ltZW50ICVpbiUgJ0VtcGxveWVkIGZ1bGwtdGltZScpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyhDb252ZXJ0ZWRTYWxhcnkpLGZpbGwgPSAiY2hvY29sYXRlMiIpICArDQogIGxhYnMoeCA9ICJBbm51YWwgU2FsYXJ5IGluIFVTRCIsIHkgPSAiRnJlcXVlbmN5IiwNCiAgICAgICB0aXRsZSA9ICIgRGlzdHJpYnV0aW9uIG9mIEFubnVhbCBTYWxhcnkgaW4gVVNEIikgKyB0aGVtZV90ZXN0KCkgLT4gc2FsDQpzYWwNCmBgYA0KTm90ZSA6IE9ubHkgdGhlIFNhbGFyeSBvZiBmdWxsIHRpbWUgZW1wbG95ZWVzIGhhdmUgYmVlbiB0YWtlbiBmb3IgdGhlIGFib3ZlIGRpc3RyaWJ1dGlvbi4NCmBgYHtyfQ0Kc3VydmV5ICU+JQ0KICBmaWx0ZXIoRW1wbG95bWVudCAlaW4lICdFbXBsb3llZCBmdWxsLXRpbWUnKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoQ29udmVydGVkU2FsYXJ5KSxmaWxsID0gImNob2NvbGF0ZTQiKSAgKw0KICBzY2FsZV94X2xvZzEwKCkgKw0KICBsYWJzKHggPSAiTG9nIEFubnVhbCBTYWxhcnkgaW4gVVNEIiwgeSA9ICJGcmVxdWVuY3kiLA0KICAgICAgIHRpdGxlID0gIiBEaXN0cmlidXRpb24gb2YgQW5udWFsIFNhbGFyeSBpbiBVU0Qgb24gTG9nIFNjYWxlIikgKyB0aGVtZV90ZXN0KCkgLT4gc2FsDQpzYWwNCmBgYA0KDQpBcyB3ZSBoYXZlIHNlZW4gaW4gdGhlIGJlZ2lubmluZyBvZiB0aGUgcHJvamVjdCwgdGhlIG1vc3QgcmVzcG9uZGVudHMgaGF2ZSBjb21lIGZyb20gdGhlIGZvbGxvd2luZyBjb3VudHJpZXMgKFRvcCAxMCkgOiBVbml0ZWQgU3RhdGVzLCBJbmRpYSwgR2VybWFueSwgVW5pdGVkIEtpbmdkb20sIENhbmFkYSwgUnVzc2lhLCBGcmFuY2UsIEJyYXppbCwgUG9sYW5kLCBBdXN0cmFsaWEgKGluIG9yZGVyKS4NCg0KTGV0IHVzIHNlZSB0aGUgZGlzdHJpYnV0aW9uICBvZiBwZW9wbGUgZnJvbSB0aGVzZSBjb3VudHJpZXMgYWxvbmUuDQoNCmBgYHtyLHJlc3VsdHM9J2hpZGUnLGZpZy5rZWVwPSdhbGwnfQ0Kc3VydmV5ICU+JSBmaWx0ZXIoRW1wbG95bWVudCAlaW4lICdFbXBsb3llZCBmdWxsLXRpbWUnKSAlPiUgDQogIGdyb3VwX2J5KENvdW50cnkpICU+JSANCiAgY291bnQoKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogIGhlYWQoMTApICU+JQ0KICBzZWxlY3QoQ291bnRyeSkgJT4lIG11dGF0ZShDb3VudHJ5ID0gZmFjdG9yKENvdW50cnkpKSAtPiBjb3VudHJpZXMNCm9wdGlvbnMoc2NpcGVuPTk5OSkNCnN1cnZleSAlPiUgZmlsdGVyKEVtcGxveW1lbnQgJWluJSAnRW1wbG95ZWQgZnVsbC10aW1lJykgJT4lIA0KICBncm91cF9ieShDb3VudHJ5KSAlPiUgDQogIG11dGF0ZShuID0gbigpKSAlPiUgDQogIGZpbHRlcihuID4gMTM1NSkgJT4lIA0KICB1bmdyb3VwKENvdW50cnkpICU+JSANCiAgZ2dwbG90KCkgKw0KICBnZW9tX3Zpb2xpbihhZXMoQ291bnRyeSxDb252ZXJ0ZWRTYWxhcnkpLCBmaWxsPSAiZGVlcHNreWJsdWU0IiwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lX21pbmltYWwoKSsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjb3VudHJpZXMkQ291bnRyeSkgKyANCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfeV9sb2cxMCgpICsNCiAgbGFicyh4ID0gIkNvdW50cnkiLCB5ID0gIkFubnVhbCBTYWxhcnkgaW4gVVNEIiwNCiAgICAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQW5udWFsIFNhbGFyeShVU0QpIG9mIFRvcCAxMCBDb3VudHJpZXMgb2YgcmVzcG9uZGVudHMiKSAtPiBwDQpnZ3Bsb3RseShwKQ0KYGBgDQoNCmBgYHtyfQ0Kb3B0aW9ucyhzY2lwZW49OTk5KQ0Kc3VydmV5ICU+JSBmaWx0ZXIoRW1wbG95bWVudCAlaW4lICdFbXBsb3llZCBmdWxsLXRpbWUnKSAlPiUgDQogIGZpbHRlcihHZW5kZXIgJWluJSBjKCdNYWxlJywnRmVtYWxlJykpICU+JSANCiAgZ3JvdXBfYnkoQ291bnRyeSkgJT4lIA0KICBtdXRhdGUobiA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKENvdW50cnkpICU+JSANCiAgZ2dwbG90KCkgKw0KICBnZW9tX2JveHBsb3QoYWVzKENvdW50cnksQ29udmVydGVkU2FsYXJ5LCBmaWxsID0gR2VuZGVyKSkgICsgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iRGFyazIiKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gY291bnRyaWVzJENvdW50cnkpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfeV9sb2cxMCgpICsgDQogIGxhYnMoeCA9ICJDb3VudHJ5IiwgeSA9ICJMb2cgb2YgQW5udWFsIFNhbGFyeSBpbiBVU0QiLA0KICAgICAgIHRpdGxlID0gIkFubnVhbCBTYWxhcnkgaW4gVVNEIC0gTWFsZSB2cyBGZW1hbGUgb2YgVG9wIDEwIGNvdW50aXJlcyBieSByZXNwb25kZW50IikgDQpgYGANCmBgYHtyfQ0Kc3VydmV5JT4lDQogIHNlbGVjdChEZXZUeXBlLENvbnZlcnRlZFNhbGFyeSxBZ2UpJT4lDQogIGZpbHRlcighaXMubmEoRGV2VHlwZSksIWlzLm5hKENvbnZlcnRlZFNhbGFyeSksIWlzLm5hKEFnZSkpICU+JQ0KICBtdXRhdGUoRGV2VHlwZT1zdHJfc3BsaXQoRGV2VHlwZSwiOyIpKSU+JQ0KICB1bm5lc3QoRGV2VHlwZSklPiVncm91cF9ieShBZ2UsRGV2VHlwZSklPiUNCiAgc3VtbWFyaXNlKGF2Z19zYWxhcnk9cm91bmQobWVkaWFuKENvbnZlcnRlZFNhbGFyeSksMCkpJT4lDQogIHVuZ3JvdXAoKSU+JQ0KICBoY2hhcnQoInNwbGluZSIsaGNhZXMoeD1BZ2UseT1hdmdfc2FsYXJ5LGdyb3VwPURldlR5cGUpKSAlPiUNCiBoY190aXRsZSh0ZXh0PSJNZWRpYW4gU2FsYXJ5IGJ5IGRldmVsb3BlciB0eXBlIGFuZCBhZ2UiKSAlPiUNCiAgaGNfeEF4aXModGl0bGU9bGlzdCh0ZXh0PSJBZ2UiKSkgJT4lDQogIGhjX3lBeGlzKHRpdGxlPWxpc3QodGV4dD0iTWVkaWFuIFNhbGFyeSBpbiBVU0QiKSkNCmBgYA0KDQpgYGB7cn0NCnN1cnZleSU+JQ0KICBzZWxlY3QoRGV2VHlwZSxDb252ZXJ0ZWRTYWxhcnkpJT4lDQogIGZpbHRlcighaXMubmEoRGV2VHlwZSksIWlzLm5hKENvbnZlcnRlZFNhbGFyeSkpJT4lDQogIG11dGF0ZShEZXZUeXBlPXN0cl9zcGxpdChEZXZUeXBlLCI7IikpJT4lDQogIHVubmVzdChEZXZUeXBlKSU+JQ0KICBncm91cF9ieShEZXZUeXBlKSU+JQ0KICBzdW1tYXJpc2UoYXZnX3NhbGFyeT1yb3VuZChtZWRpYW4oQ29udmVydGVkU2FsYXJ5KSwwKSklPiUNCiAgYXJyYW5nZShkZXNjKGF2Z19zYWxhcnkpKSU+JQ0KICB1bmdyb3VwKCklPiUgYXJyYW5nZShkZXNjKGF2Z19zYWxhcnkpKSAlPiUNCiAgaGNoYXJ0KCJsb2xsaXBvcCIsaGNhZXMoeD1EZXZUeXBlLHk9YXZnX3NhbGFyeSxncm91cD1EZXZUeXBlLHNpemU9YXZnX3NhbGFyeSkpICU+JQ0KICBoY19sZWdlbmQoZW5hYmxlZD1GQUxTRSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9Ik1lZGlhbiBTYWxhcnkgYnkgZGV2ZWxvcGVyIHR5cGUiKSAlPiUNCiAgaGNfeEF4aXModGl0bGU9bGlzdCh0ZXh0PSJEZXZlbG9wZXIgVHlwZSIpKSAlPiUNCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJNZWRpYW4gU2FsYXJ5IGluIFVTRCIpKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VydmV5JT4lDQogIHNlbGVjdChEZXZUeXBlLENvbnZlcnRlZFNhbGFyeSxZZWFyc0NvZGluZ1Byb2YpJT4lDQogIGZpbHRlcighaXMubmEoRGV2VHlwZSksIWlzLm5hKENvbnZlcnRlZFNhbGFyeSksIWlzLm5hKFllYXJzQ29kaW5nUHJvZikpJT4lDQogIG11dGF0ZShZZWFyc0NvZGluZz1wYXJzZV9udW1iZXIoYXMuY2hhcmFjdGVyKFllYXJzQ29kaW5nUHJvZikpKSU+JQ0KICBtdXRhdGUoRGV2VHlwZT1zdHJfc3BsaXQoRGV2VHlwZSwiOyIpKSU+JQ0KICB1bm5lc3QoRGV2VHlwZSklPiUNCiAgZ3JvdXBfYnkoRGV2VHlwZSklPiUNCiAgc3VtbWFyaXNlKGF2Z19zYWxhcnk9cm91bmQobWVkaWFuKENvbnZlcnRlZFNhbGFyeSksMCksbj1uKCksYXZnX3llYXJzPW1lYW4oWWVhcnNDb2RpbmcpKSU+JQ0KICBhcnJhbmdlKGRlc2MobikpJT4lDQogIHVuZ3JvdXAoKSAtPiB0DQpoY2hhcnQodCAsImJ1YmJsZSIsaGNhZXMoeD1hdmdfeWVhcnMseT1hdmdfc2FsYXJ5LGdyb3VwPURldlR5cGUsc2l6ZT1uKSkgJT4lDQogIGhjX3RpdGxlKHRleHQ9IlByb2Zlc3Npb25hbCBDb2RpbmcgRXhwZXJpZW5jZSB2cyBBdmVyYWdlIFNhbGFyeSBieSBEZXZlbG9wZXIgVHlwZSIpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9IkF2ZXJhZ2UgUHJvZmVzc2lvbmFsIENvZGluZyBFeHBlcmllbmNlIGluIFllYXJzIikpICU+JQ0KICBoY195QXhpcyh0aXRsZT1saXN0KHRleHQ9Ik1lZGlhbiBTYWxhcnkgaW4gVVNEIikpICU+JQ0KICBoY19sZWdlbmQoYWxpZ24gPSAicmlnaHQiLCBsYXlvdXQgPSAidmVydGljYWwiLCB2ZXJ0aWNhbEFsaWduID0gInRvcCIpICU+JQ0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZ29vZ2xlKCkpDQpgYGANCg0KYGBge3J9DQpzdXJ2ZXklPiUNCiAgc2VsZWN0KExhbmd1YWdlV29ya2VkV2l0aCxDb252ZXJ0ZWRTYWxhcnkpJT4lDQogIGZpbHRlcighaXMubmEoTGFuZ3VhZ2VXb3JrZWRXaXRoKSwhaXMubmEoQ29udmVydGVkU2FsYXJ5KSklPiUNCiAgbXV0YXRlKExhbmd1YWdlV29ya2VkV2l0aD1zdHJfc3BsaXQoTGFuZ3VhZ2VXb3JrZWRXaXRoLCI7IikpJT4lDQogIHVubmVzdChMYW5ndWFnZVdvcmtlZFdpdGgpJT4lDQogIGdyb3VwX2J5KExhbmd1YWdlV29ya2VkV2l0aCklPiUNCiAgc3VtbWFyaXNlKGF2Z19zYWxhcnk9cm91bmQobWVkaWFuKENvbnZlcnRlZFNhbGFyeSksMCkpJT4lDQogIGFycmFuZ2UoZGVzYyhhdmdfc2FsYXJ5KSklPiUNCiAgdW5ncm91cCgpJT4lIGFycmFuZ2UoZGVzYyhhdmdfc2FsYXJ5KSkgJT4lDQogIGhjaGFydCgibG9sbGlwb3AiLGhjYWVzKHg9TGFuZ3VhZ2VXb3JrZWRXaXRoLHk9YXZnX3NhbGFyeSxncm91cD1MYW5ndWFnZVdvcmtlZFdpdGgsc2l6ZT1hdmdfc2FsYXJ5KSkgJT4lDQogIGhjX2xlZ2VuZChlbmFibGVkPUZBTFNFKSAlPiUNCiAgaGNfdGl0bGUodGV4dD0iTWVkaWFuIFNhbGFyeSBieSBMYW5ndWFnZSBXb3JrZWQgV2l0aCIpICU+JQ0KICBoY194QXhpcyh0aXRsZT1saXN0KHRleHQ9Ikxhbmd1YWdlIFdvcmtlZCBXaXRoIikpICU+JQ0KICBoY195QXhpcyh0aXRsZT1saXN0KHRleHQ9Ik1lZGlhbiBTYWxhcnkgaW4gVVNEIikpDQpgYGANCg0KYGBge3J9DQpzdXJ2ZXklPiUNCiAgc2VsZWN0KExhbmd1YWdlV29ya2VkV2l0aCxDb252ZXJ0ZWRTYWxhcnksWWVhcnNDb2RpbmdQcm9mKSU+JQ0KICBmaWx0ZXIoIWlzLm5hKExhbmd1YWdlV29ya2VkV2l0aCksIWlzLm5hKENvbnZlcnRlZFNhbGFyeSksIWlzLm5hKFllYXJzQ29kaW5nUHJvZikpJT4lDQogIG11dGF0ZShZZWFyc0NvZGluZz1wYXJzZV9udW1iZXIoYXMuY2hhcmFjdGVyKFllYXJzQ29kaW5nUHJvZikpKSU+JQ0KICBtdXRhdGUoTGFuZ3VhZ2VXb3JrZWRXaXRoPXN0cl9zcGxpdChMYW5ndWFnZVdvcmtlZFdpdGgsIjsiKSklPiUNCiAgdW5uZXN0KExhbmd1YWdlV29ya2VkV2l0aCklPiUNCiAgZ3JvdXBfYnkoTGFuZ3VhZ2VXb3JrZWRXaXRoKSU+JQ0KICBzdW1tYXJpc2UoYXZnX3NhbGFyeT1yb3VuZChtZWRpYW4oQ29udmVydGVkU2FsYXJ5KSwwKSxuPW4oKSxhdmdfeWVhcnM9bWVhbihZZWFyc0NvZGluZykpJT4lDQogIGFycmFuZ2UoZGVzYyhuKSklPiUNCiAgdW5ncm91cCgpIC0+IHQNCmhjaGFydCh0ICwiYnViYmxlIixoY2Flcyh4PWF2Z195ZWFycyx5PWF2Z19zYWxhcnksZ3JvdXA9TGFuZ3VhZ2VXb3JrZWRXaXRoLHNpemU9bikpICU+JQ0KICBoY190aXRsZSh0ZXh0PSJQcm9mZXNzaW9uYWwgQ29kaW5nIEV4cGVyaWVuY2UgdnMgQXZlcmFnZSBTYWxhcnkgYnkgTGFuZ3VhZ2UgV29ya2VkIFdpdGgiKSAlPiUNCiAgaGNfeEF4aXModGl0bGU9bGlzdCh0ZXh0PSJBdmVyYWdlIFByb2Zlc3Npb25hbCBDb2RpbmcgRXhwZXJpZW5jZSBpbiBZZWFycyIpKSAlPiUNCiAgaGNfeUF4aXModGl0bGU9bGlzdCh0ZXh0PSJNZWRpYW4gU2FsYXJ5IGluIFVTRCIpKSAlPiUNCiAgaGNfbGVnZW5kKGFsaWduID0gInJpZ2h0IiwgbGF5b3V0ID0gInZlcnRpY2FsIiwgdmVydGljYWxBbGlnbiA9ICJ0b3AiKSAlPiUNCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2dvb2dsZSgpKQ0KYGBgDQoNClBhcnQgSVY6IE5ldHdvcmsgQW5hbHlzaXMNCg0KSW4gYSBOZXR3b3JrIHBsb3QgZm9yIFgsDQpFYWNoIG5vZGUgZGVub3RlcyB0aGUgZGlmZmVyZW50IFggdmFsdWVzIGFuZCB0aGUgc2l6ZSBvZiBub2RlIGRlbm90ZXMgdGhlIG51bWJlciBvZiByZXNwb25kZW50cyBmb3IgWC4NCkVhY2ggY29ubmVjdGluZyBlZGdlIGJldHdlZW4gYW55IHR3byBub2RlcyBkZW5vdGVzIHRoYXQgdGhlIHJlc3BvbmRlbnRzIGNob3NlIGJvdGggWCB2YWx1ZXMuIEFuZCwgdGhlIHdpZHRoIG9mIHRoZSBlZGdlIGRlbm90ZXMgdGhlIG51bWJlciBvZiB1c2VycyB0aGF0IGNob3NlIGJvdGggWCB2YWx1ZXMuDQpMZXQgdXMgbG9vayBhdCB0aGUgbmV0d29yayBwbG90cyBmb3IgRGV2ZWxvcGVyIFR5cGVzLCBMYW5ndWFnZXMgZGV2ZWxvcGVycyB3YW50IHRvIHdvcmsgd2l0aCBhbmQgSURFcyB0aGV5IHVzZS4NCg0KYGBge3IscmVzdWx0cz0naGlkZScsZmlnLmtlZXA9J2FsbCd9DQpzdXJ2ZXkgJT4lIHNlbGVjdChSZXNwb25kZW50LERldlR5cGUpIC0+IHQxDQp0MSAlPiUgDQogIG11dGF0ZShEZXZUeXBlID0gc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKERldlR5cGUpLCAiOyIpKSU+JSANCiAgdW5uZXN0KERldlR5cGUpIC0+IHQyDQogICAgICAgICANCnQyICU+JQ0KICBncm91cF9ieShSZXNwb25kZW50KSU+JQ0KICBmaWx0ZXIobigpPj0yKSU+JQ0KICBkbyhkYXRhLmZyYW1lKHQoY29tYm4oKC4pW1siRGV2VHlwZSJdXSwgMikpLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSklPiUgDQogIHVuZ3JvdXAoKSU+JQ0KICByZW5hbWUoc291cmNlID0gWDEsIHRhcmdldCA9IFgyKSU+JQ0KICBzZWxlY3QoLVJlc3BvbmRlbnQpIC0+IHQyX2VkZ2VzDQoNCnQyX2VkZ2VzICU+JSANCiAgZ3JvdXBfYnkoc291cmNlLHRhcmdldCklPiUgDQogIHN1bW1hcmlzZSh3ZWlnaHQ9bigpKSAtPnQyX2VkZ2VzDQoNCg0KbmFtZXModDJfZWRnZXMpIDwtIGMoImZyb20iLCJ0byIsIndlaWdodCIpDQp0Ml9lZGdlcyR3ZWlnaHQgPC0gdDJfZWRnZXMkd2VpZ2h0LzE1MDANCg0KdDJfZWRnZXMkd2lkdGggPC0gMSt0Ml9lZGdlcyR3ZWlnaHQNCnQyX2VkZ2VzJHNtb290aCA8LSBGQUxTRSANCnQyX2VkZ2VzJHNoYWRvdyA8LSBGQUxTRQ0KDQp0Ml9ub2RlcyA8LSB0MiAlPiUgZmlsdGVyKCFpcy5uYShEZXZUeXBlKSkgJT4lIGdyb3VwX2J5KERldlR5cGUpICU+JSBzdW1tYXJpc2UobiA9IG4oKS83NTApICU+JSBhcnJhbmdlKGRlc2MobikpDQpuYW1lcyh0Ml9ub2RlcykgPC0gYygiaWQiLCJzaXplIikNCg0KbiA8LSBucm93KHQyX25vZGVzKQ0KcGFsZXR0ZSA8LSBkaXN0aW5jdENvbG9yUGFsZXR0ZShuKQ0KDQp0Ml9ub2RlcyRzaGFwZSA8LSAiZG90IiAgDQp0Ml9ub2RlcyRzaGFkb3cgPC0gVFJVRQ0KdDJfbm9kZXMkdGl0bGUgPC0gdDJfbm9kZXMkaWQNCnQyX25vZGVzJGxhYmVsIDwtIHQyX25vZGVzJGlkDQp0Ml9ub2RlcyRzaXplIDwtIHQyX25vZGVzJHNpemUNCnQyX25vZGVzJGJvcmRlcldpZHRoIDwtIDINCg0KdDJfbm9kZXMkY29sb3IuYmFja2dyb3VuZCA8LSBwYWxldHRlW2FzLm51bWVyaWMoYXMuZmFjdG9yKHQyX25vZGVzJGlkKSldDQp0Ml9ub2RlcyRjb2xvci5ib3JkZXIgPC0gImJsYWNrIg0KdDJfbm9kZXMkY29sb3IuaGlnaGxpZ2h0LmJhY2tncm91bmQgPC0gImdvbGQiDQp0Ml9ub2RlcyRjb2xvci5oaWdobGlnaHQuYm9yZGVyIDwtICJnb2xkIg0KDQp2aXNOZXR3b3JrKHQyX25vZGVzLCB0Ml9lZGdlcyxoZWlnaHQgPSAiMTAwMHB4Iiwgd2lkdGg9IjEwMCUiKSAlPiUgdmlzSWdyYXBoTGF5b3V0KGxheW91dCA9ICJsYXlvdXRfd2l0aF9sZ2wiKSAlPiUgDQogIHZpc0VkZ2VzKHNoYWRvdyA9IFRSVUUsDQogICAgICAgICAgIGNvbG9yID0gbGlzdChjb2xvciA9ICJncmF5IiwgaGlnaGxpZ2h0ID0gImRhcmtvcmFuZ2UiKSkgJT4lIHZpc0xlZ2VuZCgpDQpgYGANCg0KRnJvbSB0aGUgbmV0d29yayBwbG90IGFib3ZlLCBpdCBjYW4gYmUgc2VlbiB0aGF0LCBpdCBjYW4gYmUgc2VlbiB0aGF0IHRoZSByZWxhdGlvbnNoaXBzIHdpdGggdGhlIGhpZ2hlc3QgY29ycmVsYXRpb24gYXJlDQpCYWNrLWVuZCBkZXZlbG9wZXIg4oCUIEZ1bGwtc3RhY2sgZGV2ZWxvcGVyDQpGcm9udC1lbmQgZGV2ZWxvcGVyIOKAlCBGdWxsLXN0YWNrIGRldmVsb3Blcg0KQmFjay1lbmQgZGV2ZWxvcGVyIOKAlCBGcm9udC1lbmQgZGV2ZWxvcGVyDQpCYWNrLWVuZCBkZXZlbG9wZXIg4oCUIERlc2t0b3Agb3IgZW50ZXJwcmlzZSBhcHBsaWNhdGlvbiBkZXZlbG9wZXINCg0KYGBge3IscmVzdWx0cz0naGlkZScsZmlnLmtlZXA9J2FsbCd9DQpzdXJ2ZXkgJT4lIHNlbGVjdChSZXNwb25kZW50LExhbmd1YWdlRGVzaXJlTmV4dFllYXIpIC0+IHQxDQp0MSAlPiUgDQogIG11dGF0ZShMYW5ndWFnZURlc2lyZU5leHRZZWFyID0gc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKExhbmd1YWdlRGVzaXJlTmV4dFllYXIpLCAiOyIpKSU+JSANCiAgdW5uZXN0KExhbmd1YWdlRGVzaXJlTmV4dFllYXIpIC0+IHQyDQogICAgICAgICANCnQyICU+JQ0KICBncm91cF9ieShSZXNwb25kZW50KSU+JQ0KICBmaWx0ZXIobigpPj0yKSU+JQ0KICBkbyhkYXRhLmZyYW1lKHQoY29tYm4oKC4pW1siTGFuZ3VhZ2VEZXNpcmVOZXh0WWVhciJdXSwgMikpLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSklPiUgDQogIHVuZ3JvdXAoKSU+JQ0KICByZW5hbWUoc291cmNlID0gWDEsIHRhcmdldCA9IFgyKSU+JQ0KICBzZWxlY3QoLVJlc3BvbmRlbnQpIC0+IHQyX2VkZ2VzDQoNCnQyX2VkZ2VzICU+JSANCiAgZ3JvdXBfYnkoc291cmNlLHRhcmdldCklPiUgDQogIHN1bW1hcmlzZSh3ZWlnaHQ9bigpKSAtPnQyX2VkZ2VzDQoNCg0KbmFtZXModDJfZWRnZXMpIDwtIGMoImZyb20iLCJ0byIsIndlaWdodCIpDQp0Ml9lZGdlcyR3ZWlnaHQgPC0gdDJfZWRnZXMkd2VpZ2h0LzE1MDANCg0KdDJfZWRnZXMkd2lkdGggPC0gMSt0Ml9lZGdlcyR3ZWlnaHQNCnQyX2VkZ2VzJHNtb290aCA8LSBGQUxTRSANCnQyX2VkZ2VzJHNoYWRvdyA8LSBGQUxTRQ0KDQp0Ml9ub2RlcyA8LSB0MiAlPiUgZmlsdGVyKCFpcy5uYShMYW5ndWFnZURlc2lyZU5leHRZZWFyKSkgJT4lIGdyb3VwX2J5KExhbmd1YWdlRGVzaXJlTmV4dFllYXIpICU+JSBzdW1tYXJpc2UobiA9IG4oKS83NTApICU+JSBhcnJhbmdlKGRlc2MobikpDQpuYW1lcyh0Ml9ub2RlcykgPC0gYygiaWQiLCJzaXplIikNCg0KbiA8LSBucm93KHQyX25vZGVzKQ0KcGFsZXR0ZSA8LSBkaXN0aW5jdENvbG9yUGFsZXR0ZShuKQ0KDQp0Ml9ub2RlcyRzaGFwZSA8LSAiY2lyY2xlIiAgDQp0Ml9ub2RlcyRzaGFkb3cgPC0gVFJVRQ0KdDJfbm9kZXMkdGl0bGUgPC0gdDJfbm9kZXMkaWQNCnQyX25vZGVzJGxhYmVsIDwtIHQyX25vZGVzJGlkDQp0Ml9ub2RlcyRzaXplIDwtIHQyX25vZGVzJHNpemUNCnQyX25vZGVzJGJvcmRlcldpZHRoIDwtIDINCg0KdDJfbm9kZXMkY29sb3IuYmFja2dyb3VuZCA8LSBwYWxldHRlW2FzLm51bWVyaWMoYXMuZmFjdG9yKHQyX25vZGVzJGlkKSldDQp0Ml9ub2RlcyRjb2xvci5ib3JkZXIgPC0gImJsYWNrIg0KdDJfbm9kZXMkY29sb3IuaGlnaGxpZ2h0LmJhY2tncm91bmQgPC0gInB1cnBsZSINCnQyX25vZGVzJGNvbG9yLmhpZ2hsaWdodC5ib3JkZXIgPC0gInB1cnBsZSINCg0KdmlzTmV0d29yayh0Ml9ub2RlcywgdDJfZWRnZXMsaGVpZ2h0ID0gIjEyMDBweCIsIHdpZHRoPSIxMDAlIikgJT4lIHZpc0lncmFwaExheW91dChsYXlvdXQgPSAibGF5b3V0X3dpdGhfbGdsIikgJT4lIA0KICB2aXNFZGdlcyhzaGFkb3cgPSBUUlVFLA0KICAgICAgICAgICBjb2xvciA9IGxpc3QoY29sb3IgPSAiZ3JheSIsIGhpZ2hsaWdodCA9ICJtYWdlbnRhIikpICU+JSB2aXNMZWdlbmQoKQ0KYGBgDQpUaGUgcmVsYXRpb25zaGlwcyB3aXRoIGhpZ2hlc3QgY29ycmVsYXRpb24gYXJlOg0KSFRNTCDigJQgQ1NTDQpIVE1MIOKAlCBKYXZhU2NyaXB0DQpDU1Mg4oCUIEphdmFTY3JpcHQNCkhUTUwg4oCUIFNRTA0KU1FMIOKAlCBKYXZhU2NyaXB0DQpDU1Mg4oCUIFNRTA0KUHl0aG9uIOKAlCBTUUwNClB5dGhvbiDigJQgSmF2YVNjcmlwdA0KDQpgYGB7cixyZXN1bHRzPSdoaWRlJyxmaWcua2VlcD0nYWxsJ30NCnN1cnZleSAlPiUgc2VsZWN0KFJlc3BvbmRlbnQsSURFKSAtPiB0MQ0KdDEgJT4lIA0KICBtdXRhdGUoSURFID0gc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKElERSksICI7IikpJT4lIA0KICB1bm5lc3QoSURFKSAtPiB0Mg0KICAgICAgICAgDQp0MiAlPiUNCiAgZ3JvdXBfYnkoUmVzcG9uZGVudCklPiUNCiAgZmlsdGVyKG4oKT49MiklPiUNCiAgZG8oZGF0YS5mcmFtZSh0KGNvbWJuKCguKVtbIklERSJdXSwgMikpLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSklPiUgDQogIHVuZ3JvdXAoKSU+JQ0KICByZW5hbWUoc291cmNlID0gWDEsIHRhcmdldCA9IFgyKSU+JQ0KICBzZWxlY3QoLVJlc3BvbmRlbnQpIC0+dDJfZWRnZXMNCg0KdDJfZWRnZXMgJT4lIA0KICBncm91cF9ieShzb3VyY2UsdGFyZ2V0KSU+JSANCiAgc3VtbWFyaXNlKHdlaWdodD1uKCkpIC0+dDJfZWRnZXMNCg0KDQpuYW1lcyh0Ml9lZGdlcykgPC0gYygiZnJvbSIsInRvIiwid2VpZ2h0IikNCnQyX2VkZ2VzJHdlaWdodCA8LSB0Ml9lZGdlcyR3ZWlnaHQvMTUwMA0KDQp0Ml9lZGdlcyR3aWR0aCA8LSAxK3QyX2VkZ2VzJHdlaWdodA0KdDJfZWRnZXMkc21vb3RoIDwtIEZBTFNFIA0KdDJfZWRnZXMkc2hhZG93IDwtIEZBTFNFDQoNCnQyX25vZGVzIDwtIHQyICU+JSBmaWx0ZXIoIWlzLm5hKElERSkpICU+JSBncm91cF9ieShJREUpICU+JSBzdW1tYXJpc2UobiA9IG4oKS83NTApICU+JSBhcnJhbmdlKGRlc2MobikpDQpuYW1lcyh0Ml9ub2RlcykgPC0gYygiaWQiLCJzaXplIikNCg0KbiA8LSBucm93KHQyX25vZGVzKQ0KcGFsZXR0ZSA8LSBkaXN0aW5jdENvbG9yUGFsZXR0ZShuKQ0KDQp0Ml9ub2RlcyRzaGFwZSA8LSAidHJpYW5nbGUiICANCnQyX25vZGVzJHNoYWRvdyA8LSBUUlVFDQp0Ml9ub2RlcyR0aXRsZSA8LSB0Ml9ub2RlcyRpZA0KdDJfbm9kZXMkbGFiZWwgPC0gdDJfbm9kZXMkaWQNCnQyX25vZGVzJHNpemUgPC0gdDJfbm9kZXMkc2l6ZQ0KdDJfbm9kZXMkYm9yZGVyV2lkdGggPC0gMg0KDQp0Ml9ub2RlcyRjb2xvci5iYWNrZ3JvdW5kIDwtIHBhbGV0dGVbYXMubnVtZXJpYyhhcy5mYWN0b3IodDJfbm9kZXMkaWQpKV0NCnQyX25vZGVzJGNvbG9yLmJvcmRlciA8LSAiYmxhY2siDQp0Ml9ub2RlcyRjb2xvci5oaWdobGlnaHQuYmFja2dyb3VuZCA8LSAiY2hvY29sYXRlIg0KdDJfbm9kZXMkY29sb3IuaGlnaGxpZ2h0LmJvcmRlciA8LSAiY2hvY29sYXRlIg0KDQp2aXNOZXR3b3JrKHQyX25vZGVzLCB0Ml9lZGdlcyxoZWlnaHQgPSAiMTAwMHB4Iiwgd2lkdGg9IjEwMCUiKSAlPiUgdmlzSWdyYXBoTGF5b3V0KGxheW91dCA9ICJsYXlvdXRfd2l0aF9sZ2wiKSAlPiUgDQogIHZpc0VkZ2VzKHNoYWRvdyA9IFRSVUUsDQogICAgICAgICAgIGNvbG9yID0gbGlzdChjb2xvciA9ICJncmF5IiwgaGlnaGxpZ2h0ID0gImJyb3duIikpICU+JSB2aXNMZWdlbmQoKQ0KYGBgDQpgYGANCg0K